Skip to content

Commit bff65c6

Browse files
authored
feat(as): add support for apple silicon M1-M (#776)
1 parent 96511c8 commit bff65c6

7 files changed

+549
-3
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/google/go-cmp v0.5.4
88
github.com/hashicorp/go-retryablehttp v0.6.8
99
github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.0
10-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210122093136-86a7a7845e32
10+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210202173413-337fb17121a1
1111
github.com/stretchr/testify v1.6.1
1212
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
1313
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
315315
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
316316
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
317317
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
318-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210122093136-86a7a7845e32 h1:XEqVuIfQTWwFfeBJZ0rxXoeT2blrKefX01TtUrxg+y0=
319-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210122093136-86a7a7845e32/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
318+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210202173413-337fb17121a1 h1:vytHInJpH5I4FheLyFW2wu5LmtcQOJhetm3+jaVGp74=
319+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210202173413-337fb17121a1/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
320320
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
321321
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
322322
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=

scaleway/helpers_apple_silicon.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package scaleway
2+
3+
import (
4+
"time"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7+
applesilicon "github.com/scaleway/scaleway-sdk-go/api/applesilicon/v1alpha1"
8+
"github.com/scaleway/scaleway-sdk-go/scw"
9+
)
10+
11+
const (
12+
defaultAppleSiliconServerTimeout = 2 * time.Minute
13+
)
14+
15+
// asAPIWithZone returns a new apple silicon API and the zone
16+
func asAPIWithZone(d *schema.ResourceData, m interface{}) (*applesilicon.API, scw.Zone, error) {
17+
meta := m.(*Meta)
18+
asAPI := applesilicon.NewAPI(meta.scwClient)
19+
20+
zone, err := extractZone(d, meta)
21+
if err != nil {
22+
return nil, "", err
23+
}
24+
return asAPI, zone, nil
25+
}
26+
27+
// asAPIWithZoneAndID returns an apple silicon API with zone and ID extracted from the state
28+
func asAPIWithZoneAndID(m interface{}, id string) (*applesilicon.API, scw.Zone, string, error) {
29+
meta := m.(*Meta)
30+
asAPI := applesilicon.NewAPI(meta.scwClient)
31+
32+
zone, ID, err := parseZonedID(id)
33+
if err != nil {
34+
return nil, "", "", err
35+
}
36+
return asAPI, zone, ID, nil
37+
}

scaleway/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ func Provider(config *ProviderConfig) plugin.ProviderFunc {
6666

6767
ResourcesMap: map[string]*schema.Resource{
6868
"scaleway_account_ssh_key": resourceScalewayAccountSSKKey(),
69+
"scaleway_apple_silicon_server": resourceScalewayAppleSiliconServer(),
6970
"scaleway_baremetal_server": resourceScalewayBaremetalServer(),
7071
"scaleway_instance_ip": resourceScalewayInstanceIP(),
7172
"scaleway_instance_ip_reverse_dns": resourceScalewayInstanceIPReverseDNS(),
+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package scaleway
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
applesilicon "github.com/scaleway/scaleway-sdk-go/api/applesilicon/v1alpha1"
10+
"github.com/scaleway/scaleway-sdk-go/scw"
11+
)
12+
13+
func resourceScalewayAppleSiliconServer() *schema.Resource {
14+
return &schema.Resource{
15+
CreateContext: resourceScalewayAppleSiliconServerCreate,
16+
ReadContext: resourceScalewayAppleSiliconServerRead,
17+
UpdateContext: resourceScalewayAppleSiliconServerUpdate,
18+
DeleteContext: resourceScalewayAppleSiliconServerDelete,
19+
Timeouts: &schema.ResourceTimeout{
20+
Default: schema.DefaultTimeout(defaultAppleSiliconServerTimeout),
21+
},
22+
Importer: &schema.ResourceImporter{
23+
StateContext: schema.ImportStatePassthroughContext,
24+
},
25+
SchemaVersion: 0,
26+
Schema: map[string]*schema.Schema{
27+
"name": {
28+
Type: schema.TypeString,
29+
Description: "Name of the server",
30+
Computed: true,
31+
Optional: true,
32+
},
33+
"type": {
34+
Type: schema.TypeString,
35+
Description: "Type of the server",
36+
Required: true,
37+
ForceNew: true,
38+
},
39+
40+
// Computed
41+
"ip": {
42+
Type: schema.TypeString,
43+
Description: "IPv4 address of the server",
44+
Computed: true,
45+
},
46+
"vnc_url": {
47+
Type: schema.TypeString,
48+
Description: "VNC url use to connect remotely to the desktop GUI",
49+
Computed: true,
50+
},
51+
52+
"created_at": {
53+
Type: schema.TypeString,
54+
Computed: true,
55+
Description: "The date and time of the creation of the server",
56+
},
57+
"updated_at": {
58+
Type: schema.TypeString,
59+
Computed: true,
60+
Description: "The date and time of the last update of the server",
61+
},
62+
"deletable_at": {
63+
Type: schema.TypeString,
64+
Computed: true,
65+
Description: "The minimal date and time on which you can delete this server due to Apple licence",
66+
},
67+
68+
// Common
69+
"zone": zoneSchema(),
70+
"organization_id": organizationIDSchema(),
71+
"project_id": projectIDSchema(),
72+
},
73+
}
74+
}
75+
76+
func resourceScalewayAppleSiliconServerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
77+
asAPI, zone, err := asAPIWithZone(d, m)
78+
if err != nil {
79+
return diag.FromErr(err)
80+
}
81+
82+
createReq := &applesilicon.CreateServerRequest{
83+
Name: expandOrGenerateString(d.Get("name"), "m1"),
84+
Type: d.Get("type").(string),
85+
ProjectID: d.Get("project_id").(string),
86+
}
87+
88+
res, err := asAPI.CreateServer(createReq, scw.WithContext(ctx))
89+
if err != nil {
90+
return diag.FromErr(err)
91+
}
92+
93+
d.SetId(newZonedIDString(zone, res.ID))
94+
95+
_, err = asAPI.WaitForServer(&applesilicon.WaitForServerRequest{
96+
ServerID: res.ID,
97+
Timeout: scw.TimeDurationPtr(defaultAppleSiliconServerTimeout),
98+
RetryInterval: nil,
99+
}, scw.WithContext(ctx))
100+
if err != nil {
101+
return diag.FromErr(err)
102+
}
103+
104+
return resourceScalewayRdbInstanceRead(ctx, d, m)
105+
}
106+
107+
func resourceScalewayAppleSiliconServerRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
108+
asAPI, zone, ID, err := asAPIWithZoneAndID(m, d.Id())
109+
if err != nil {
110+
return diag.FromErr(err)
111+
}
112+
113+
res, err := asAPI.GetServer(&applesilicon.GetServerRequest{
114+
Zone: zone,
115+
ServerID: ID,
116+
}, scw.WithContext(ctx))
117+
if err != nil {
118+
if is404Error(err) {
119+
d.SetId("")
120+
return nil
121+
}
122+
return diag.FromErr(err)
123+
}
124+
125+
_ = d.Set("name", res.Name)
126+
_ = d.Set("type", res.Type)
127+
_ = d.Set("created_at", res.CreatedAt.Format(time.RFC3339))
128+
_ = d.Set("updated_at", res.UpdatedAt.Format(time.RFC3339))
129+
_ = d.Set("deletable_at", res.DeletableAt.Format(time.RFC3339))
130+
_ = d.Set("ip", res.IP.String())
131+
_ = d.Set("vnc_url", res.VncURL)
132+
133+
_ = d.Set("zone", zone.String())
134+
_ = d.Set("organization_id", res.OrganizationID)
135+
_ = d.Set("project_id", res.ProjectID)
136+
137+
return nil
138+
}
139+
140+
func resourceScalewayAppleSiliconServerUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
141+
asAPI, zone, ID, err := asAPIWithZoneAndID(m, d.Id())
142+
if err != nil {
143+
return diag.FromErr(err)
144+
}
145+
146+
req := &applesilicon.UpdateServerRequest{
147+
Zone: zone,
148+
ServerID: ID,
149+
}
150+
151+
if d.HasChange("name") {
152+
req.Name = expandStringPtr(d.Get("name"))
153+
}
154+
155+
_, err = asAPI.UpdateServer(req, scw.WithContext(ctx))
156+
if err != nil {
157+
return diag.FromErr(err)
158+
}
159+
160+
return resourceScalewayAppleSiliconServerRead(ctx, d, m)
161+
}
162+
163+
func resourceScalewayAppleSiliconServerDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
164+
asAPI, zone, ID, err := asAPIWithZoneAndID(m, d.Id())
165+
if err != nil {
166+
return diag.FromErr(err)
167+
}
168+
169+
err = asAPI.DeleteServer(&applesilicon.DeleteServerRequest{
170+
Zone: zone,
171+
ServerID: ID,
172+
}, scw.WithContext(ctx))
173+
174+
if err != nil && !is404Error(err) {
175+
return diag.FromErr(err)
176+
}
177+
178+
return nil
179+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
9+
applesilicon "github.com/scaleway/scaleway-sdk-go/api/applesilicon/v1alpha1"
10+
"github.com/scaleway/scaleway-sdk-go/scw"
11+
)
12+
13+
func init() {
14+
resource.AddTestSweepers("scaleway_apple_silicon_instance", &resource.Sweeper{
15+
Name: "scaleway_apple_silicon",
16+
F: testSweepAppleSiliconServer,
17+
})
18+
}
19+
20+
func testSweepAppleSiliconServer(_ string) error {
21+
return sweepZones(scw.AllZones, func(scwClient *scw.Client, zone scw.Zone) error {
22+
asAPI := applesilicon.NewAPI(scwClient)
23+
l.Debugf("sweeper: destroying the apple silicon instance in (%s)", zone)
24+
listServers, err := asAPI.ListServers(&applesilicon.ListServersRequest{}, scw.WithAllPages())
25+
if err != nil {
26+
return fmt.Errorf("error listing apple silicon servers in (%s) in sweeper: %s", zone, err)
27+
}
28+
29+
for _, server := range listServers.Servers {
30+
errDelete := asAPI.DeleteServer(&applesilicon.DeleteServerRequest{
31+
ServerID: server.ID,
32+
Zone: zone,
33+
})
34+
if errDelete != nil {
35+
return fmt.Errorf("error deleting apple silicon server in sweeper: %s", err)
36+
}
37+
}
38+
39+
return nil
40+
})
41+
}
42+
43+
func TestAccScalewayAppleSiliconServer_Basic(t *testing.T) {
44+
tt := NewTestTools(t)
45+
defer tt.Cleanup()
46+
resource.ParallelTest(t, resource.TestCase{
47+
PreCheck: func() { testAccPreCheck(t) },
48+
ProviderFactories: tt.ProviderFactories,
49+
CheckDestroy: testAccCheckScalewayAppleSiliconServerDestroy(tt),
50+
Steps: []resource.TestStep{
51+
{
52+
Config: `
53+
resource scaleway_apple_silicon_server main {
54+
name = "test-m1"
55+
type = "M1-M"
56+
}
57+
`,
58+
Check: resource.ComposeTestCheckFunc(
59+
testAccCheckScalewayAppleSiliconExists(tt, "scaleway_apple_silicon_server.main"),
60+
resource.TestCheckResourceAttr("scaleway_apple_silicon_server.main", "name", "test-m1"),
61+
resource.TestCheckResourceAttr("scaleway_apple_silicon_server.main", "type", "M1-M"),
62+
// Computed
63+
resource.TestCheckResourceAttrSet("scaleway_apple_silicon_server.main", "ip"),
64+
resource.TestCheckResourceAttrSet("scaleway_apple_silicon_server.main", "vnc_url"),
65+
resource.TestCheckResourceAttrSet("scaleway_apple_silicon_server.main", "created_at"),
66+
resource.TestCheckResourceAttrSet("scaleway_apple_silicon_server.main", "deletable_at"),
67+
),
68+
},
69+
},
70+
})
71+
}
72+
73+
func testAccCheckScalewayAppleSiliconExists(tt *TestTools, n string) resource.TestCheckFunc {
74+
return func(s *terraform.State) error {
75+
rs, ok := s.RootModule().Resources[n]
76+
if !ok {
77+
return fmt.Errorf("resource not found: %s", n)
78+
}
79+
80+
asAPI, zone, ID, err := asAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
81+
if err != nil {
82+
return err
83+
}
84+
85+
_, err = asAPI.GetServer(&applesilicon.GetServerRequest{
86+
ServerID: ID,
87+
Zone: zone,
88+
})
89+
90+
if err != nil {
91+
return err
92+
}
93+
94+
return nil
95+
}
96+
}
97+
98+
func testAccCheckScalewayAppleSiliconServerDestroy(tt *TestTools) resource.TestCheckFunc {
99+
return func(state *terraform.State) error {
100+
for _, rs := range state.RootModule().Resources {
101+
if rs.Type != "scaleway_apple_silicon_server" {
102+
continue
103+
}
104+
105+
asAPI, zone, ID, err := asAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
106+
if err != nil {
107+
return err
108+
}
109+
110+
_, err = asAPI.GetServer(&applesilicon.GetServerRequest{
111+
ServerID: ID,
112+
Zone: zone,
113+
})
114+
115+
// If no error resource still exist
116+
if err == nil {
117+
return fmt.Errorf("server (%s) still exists", rs.Primary.ID)
118+
}
119+
120+
// Unexpected api error we return it
121+
if !is404Error(err) {
122+
return err
123+
}
124+
}
125+
126+
return nil
127+
}
128+
}

0 commit comments

Comments
 (0)