Skip to content

Commit

Permalink
tailscale: add support for using v2 tailscale-client
Browse files Browse the repository at this point in the history
Updates tailscale/corp#21867

Signed-off-by: Percy Wegmann <percy@tailscale.com>
  • Loading branch information
oxtoacart committed Aug 2, 2024
1 parent 6bc9542 commit 95ac057
Show file tree
Hide file tree
Showing 22 changed files with 135 additions and 101 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/stretchr/testify v1.9.0
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a
github.com/tailscale/tailscale-client-go v1.17.1-0.20240729175651-90a1e935cc19
github.com/tailscale/tailscale-client-go/v2 v2.0.0-20240801195603-6096900af9df
golang.org/x/tools v0.23.0
tailscale.com v1.70.0
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29X
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8=
github.com/tailscale/tailscale-client-go v1.17.1-0.20240729175651-90a1e935cc19 h1:fRLv1yZH1ueL1cnpLhOnOymoBfMCIviCn0e0VkAjkK4=
github.com/tailscale/tailscale-client-go v1.17.1-0.20240729175651-90a1e935cc19/go.mod h1:jbwJyHniK3nyLttwcDTXnfdDQEnADvc4VMOP8hZWnR0=
github.com/tailscale/tailscale-client-go/v2 v2.0.0-20240801195603-6096900af9df h1:XjHI0pFxhttM1nEn/WNGOO3wrJYEJSZarJm0i5WFXgY=
github.com/tailscale/tailscale-client-go/v2 v2.0.0-20240801195603-6096900af9df/go.mod h1:i/MSgQ71kdyh1Wdp50XxrIgtsyO4uZ2SZSPd83lGKHM=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
Expand Down
3 changes: 1 addition & 2 deletions tailscale/data_source_acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/tailscale/hujson"
"github.com/tailscale/tailscale-client-go/tailscale"
)

func dataSourceACL() *schema.Resource {
Expand All @@ -30,7 +29,7 @@ func dataSourceACL() *schema.Resource {
}

func dataSourceACLRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

acl, err := client.RawACL(ctx)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion tailscale/data_source_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func dataSourceDevice() *schema.Resource {
}

func dataSourceDeviceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

var filter func(d tailscale.Device) bool
var filterDesc string
Expand Down
4 changes: 1 addition & 3 deletions tailscale/data_source_devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/tailscale/tailscale-client-go/tailscale"
)

func dataSourceDevices() *schema.Resource {
Expand Down Expand Up @@ -70,7 +68,7 @@ func dataSourceDevices() *schema.Resource {
}

func dataSourceDevicesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

devices, err := client.Devices(ctx)
if err != nil {
Expand Down
31 changes: 29 additions & 2 deletions tailscale/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package tailscale
import (
"context"
"fmt"
"net/url"
"time"

"github.com/hashicorp/go-cty/cty"
Expand All @@ -13,13 +14,20 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/tailscale/tailscale-client-go/tailscale"
tailscalev2 "github.com/tailscale/tailscale-client-go/v2"
)

// providerVersion is filled by goreleaser at build time.
var providerVersion = "dev"

type ProviderOption func(p *schema.Provider)

// Clients contains both v1 and v2 Tailscale Clients
type Clients struct {
V1 *tailscale.Client
V2 *tailscalev2.Client
}

// Provider returns the *schema.Provider instance that implements the terraform provider.
func Provider(options ...ProviderOption) *schema.Provider {
// Support both sets of OAuth Env vars for backwards compatibility
Expand Down Expand Up @@ -107,6 +115,11 @@ func Provider(options ...ProviderOption) *schema.Provider {

func providerConfigure(_ context.Context, provider *schema.Provider, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
baseURL := d.Get("base_url").(string)
parsedBaseURL, err := url.Parse(baseURL)
if err != nil {
return nil, diag.Errorf("could not parse baseURL %q: %s", baseURL, err)
}

tailnet := d.Get("tailnet").(string)
if tailnet == "" {
return nil, diag.Errorf("tailscale provider argument 'tailnet' is empty")
Expand Down Expand Up @@ -152,7 +165,14 @@ func providerConfigure(_ context.Context, provider *schema.Provider, d *schema.R
return nil, diagnosticsError(err, "failed to initialise client")
}

return client, nil
clientV2 := &tailscalev2.Client{
BaseURL: parsedBaseURL,
UserAgent: userAgent,
Tailnet: tailnet,
}
clientV2.UseOAuth(oauthClientID, oauthClientSecret, oauthScopes)

return &Clients{client, clientV2}, nil
}

client, err := tailscale.NewClient(
Expand All @@ -165,7 +185,14 @@ func providerConfigure(_ context.Context, provider *schema.Provider, d *schema.R
return nil, diagnosticsError(err, "failed to initialise client")
}

return client, nil
clientV2 := &tailscalev2.Client{
BaseURL: parsedBaseURL,
UserAgent: userAgent,
APIKey: apiKey,
Tailnet: tailnet,
}

return &Clients{client, clientV2}, nil
}

func diagnosticsError(err error, message string, args ...interface{}) diag.Diagnostics {
Expand Down
7 changes: 3 additions & 4 deletions tailscale/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

ts "github.com/tailscale/tailscale-client-go/tailscale"
"github.com/tailscale/terraform-provider-tailscale/tailscale"
)

var testClient *ts.Client
var testClients *tailscale.Clients
var testServer *TestServer
var testAccProvider = tailscale.Provider()

Expand Down Expand Up @@ -66,13 +65,13 @@ func TestProvider_Implemented(t *testing.T) {
func testProviderFactories(t *testing.T) map[string]func() (*schema.Provider, error) {
t.Helper()

testClient, testServer = NewTestHarness(t)
testClients, testServer = NewTestHarness(t)
return map[string]func() (*schema.Provider, error){
"tailscale": func() (*schema.Provider, error) {
return tailscale.Provider(func(p *schema.Provider) {
// Set up a test harness for the provider
p.ConfigureContextFunc = func(ctx context.Context, data *schema.ResourceData) (interface{}, diag.Diagnostics) {
return testClient, nil
return testClients, nil
}

// Don't require any of the global configuration
Expand Down
8 changes: 4 additions & 4 deletions tailscale/resource_acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func resourceACL() *schema.Resource {
StateContext: schema.ImportStatePassthroughContext,
},
CustomizeDiff: func(ctx context.Context, rd *schema.ResourceDiff, m interface{}) error {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

//if the acl is only known after apply, then acl will be an empty string and validation will fail
if rd.Get("acl").(string) == "" {
Expand Down Expand Up @@ -97,7 +97,7 @@ func resourceACL() *schema.Resource {
}

func resourceACLRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1
acl, err := client.RawACL(ctx)
if err != nil {
return diagnosticsError(err, "Failed to fetch ACL")
Expand All @@ -110,7 +110,7 @@ func resourceACLRead(ctx context.Context, d *schema.ResourceData, m interface{})
}

func resourceACLCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1
acl := d.Get("acl").(string)

// Setting the `ts-default` ETag will make this operation succeed only if
Expand All @@ -136,7 +136,7 @@ func resourceACLCreate(ctx context.Context, d *schema.ResourceData, m interface{
}

func resourceACLUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

if !d.HasChange("acl") {
return nil
Expand Down
6 changes: 3 additions & 3 deletions tailscale/resource_contacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func resourceContacts() *schema.Resource {
}

func resourceContactsCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

if diagErr := updateContact(ctx, client, d, tailscale.ContactAccount); diagErr != nil {
return diagErr
Expand All @@ -94,7 +94,7 @@ func resourceContactsCreate(ctx context.Context, d *schema.ResourceData, m inter
}

func resourceContactsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

contacts, err := client.Contacts(ctx)
if err != nil {
Expand All @@ -117,7 +117,7 @@ func resourceContactsRead(ctx context.Context, d *schema.ResourceData, m interfa
}

func resourceContactsUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1

if d.HasChange("account") {
if diagErr := updateContact(ctx, client, d, tailscale.ContactAccount); diagErr != nil {
Expand Down
37 changes: 19 additions & 18 deletions tailscale/resource_contacts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

"github.com/tailscale/tailscale-client-go/tailscale"
tsclient "github.com/tailscale/tailscale-client-go/tailscale"
"github.com/tailscale/terraform-provider-tailscale/tailscale"
)

const testContactsBasic = `
Expand Down Expand Up @@ -41,32 +42,32 @@ const testContactsUpdated = `
}
}`

var expectedContactsBasic = &tailscale.Contacts{
Account: tailscale.Contact{
var expectedContactsBasic = &tsclient.Contacts{
Account: tsclient.Contact{
Email: "account@example.com",
},
Support: tailscale.Contact{
Support: tsclient.Contact{
Email: "support@example.com",
},
Security: tailscale.Contact{
Security: tsclient.Contact{
Email: "security@example.com",
},
}

var expectedContactsUpdated = &tailscale.Contacts{
Account: tailscale.Contact{
var expectedContactsUpdated = &tsclient.Contacts{
Account: tsclient.Contact{
Email: "otheraccount@example.com",
},
Support: tailscale.Contact{
Support: tsclient.Contact{
Email: "support@example.com",
},
Security: tailscale.Contact{
Security: tsclient.Contact{
Email: "security2@example.com",
},
}

func TestAccTailscaleContacts_Basic(t *testing.T) {
contacts := &tailscale.Contacts{}
contacts := &tsclient.Contacts{}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -93,7 +94,7 @@ func TestAccTailscaleContacts_Basic(t *testing.T) {
}

func TestAccTailscaleContacts_Update(t *testing.T) {
contacts := &tailscale.Contacts{}
contacts := &tsclient.Contacts{}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down Expand Up @@ -129,7 +130,7 @@ func TestAccTailscaleContacts_Update(t *testing.T) {
})
}

func testAccCheckContactsExists(resourceName string, contacts *tailscale.Contacts) resource.TestCheckFunc {
func testAccCheckContactsExists(resourceName string, contacts *tsclient.Contacts) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
Expand All @@ -140,7 +141,7 @@ func testAccCheckContactsExists(resourceName string, contacts *tailscale.Contact
return fmt.Errorf("resource has no ID set")
}

client := testAccProvider.Meta().(*tailscale.Client)
client := testAccProvider.Meta().(*tailscale.Clients).V1
out, err := client.Contacts(context.Background())
if err != nil {
return err
Expand All @@ -151,7 +152,7 @@ func testAccCheckContactsExists(resourceName string, contacts *tailscale.Contact
}
}

func testAccCheckContactsPropertiesBasic(contacts *tailscale.Contacts) resource.TestCheckFunc {
func testAccCheckContactsPropertiesBasic(contacts *tsclient.Contacts) resource.TestCheckFunc {
return func(s *terraform.State) error {
if err := checkContacts(contacts, expectedContactsBasic); err != nil {
return err
Expand All @@ -161,7 +162,7 @@ func testAccCheckContactsPropertiesBasic(contacts *tailscale.Contacts) resource.
}
}

func testAccCheckContactsPropertiesUpdated(contacts *tailscale.Contacts) resource.TestCheckFunc {
func testAccCheckContactsPropertiesUpdated(contacts *tsclient.Contacts) resource.TestCheckFunc {
return func(s *terraform.State) error {
if err := checkContacts(contacts, expectedContactsUpdated); err != nil {
return err
Expand All @@ -179,8 +180,8 @@ func testAccCheckContactsDestroyUpdated(s *terraform.State) error {
return testAccCheckContactsDestroy(s, expectedContactsUpdated)
}

func testAccCheckContactsDestroy(s *terraform.State, expectedContacts *tailscale.Contacts) error {
client := testAccProvider.Meta().(*tailscale.Client)
func testAccCheckContactsDestroy(s *terraform.State, expectedContacts *tsclient.Contacts) error {
client := testAccProvider.Meta().(*tailscale.Clients).V1

for _, rs := range s.RootModule().Resources {
if rs.Type != "tailscale_contacts" {
Expand All @@ -203,7 +204,7 @@ func testAccCheckContactsDestroy(s *terraform.State, expectedContacts *tailscale
return nil
}

func checkContacts(contacts *tailscale.Contacts, expectedContacts *tailscale.Contacts) error {
func checkContacts(contacts *tsclient.Contacts, expectedContacts *tsclient.Contacts) error {
if contacts.Account.Email != expectedContacts.Account.Email {
return fmt.Errorf("bad account email, expected %q, got %q", expectedContacts.Account.Email, contacts.Account.Email)
}
Expand Down
6 changes: 3 additions & 3 deletions tailscale/resource_device_authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func resourceDeviceAuthorization() *schema.Resource {
}

func resourceDeviceAuthorizationRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1
deviceID := d.Get("device_id").(string)

devices, err := client.Devices(ctx)
Expand Down Expand Up @@ -60,7 +60,7 @@ func resourceDeviceAuthorizationRead(ctx context.Context, d *schema.ResourceData
}

func resourceDeviceAuthorizationCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1
deviceID := d.Get("device_id").(string)
authorized := d.Get("authorized").(bool)

Expand All @@ -75,7 +75,7 @@ func resourceDeviceAuthorizationCreate(ctx context.Context, d *schema.ResourceDa
}

func resourceDeviceAuthorizationUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*tailscale.Client)
client := m.(*Clients).V1
deviceID := d.Get("device_id").(string)

devices, err := client.Devices(ctx)
Expand Down
Loading

0 comments on commit 95ac057

Please sign in to comment.