Skip to content

Commit 40fc5fa

Browse files
committed
feat(domain): add support for buying and registar domains
1 parent d70615f commit 40fc5fa

File tree

2 files changed

+298
-0
lines changed

2 files changed

+298
-0
lines changed

internal/services/domain/domain.go

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
package domain
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
domain "github.com/scaleway/scaleway-sdk-go/api/domain/v2beta1"
9+
"github.com/scaleway/scaleway-sdk-go/scw"
10+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/account"
11+
)
12+
13+
func resourceDomain() *schema.Resource {
14+
return &schema.Resource{
15+
CreateContext: resourceDomainCreate,
16+
ReadContext: resourceDomainsRead,
17+
Timeouts: &schema.ResourceTimeout{
18+
Create: schema.DefaultTimeout(defaultDomainRecordTimeout),
19+
Read: schema.DefaultTimeout(defaultDomainRecordTimeout),
20+
Update: schema.DefaultTimeout(defaultDomainRecordTimeout),
21+
Delete: schema.DefaultTimeout(defaultDomainRecordTimeout),
22+
Default: schema.DefaultTimeout(defaultDomainRecordTimeout),
23+
},
24+
Importer: &schema.ResourceImporter{
25+
StateContext: schema.ImportStatePassthroughContext,
26+
},
27+
SchemaVersion: 0,
28+
29+
Schema: map[string]*schema.Schema{
30+
"domain_names": {
31+
Type: schema.TypeList,
32+
Required: true,
33+
Elem: &schema.Schema{
34+
Type: schema.TypeString,
35+
},
36+
Description: "List of domain names to be managed",
37+
},
38+
"duration_in_years": {
39+
Type: schema.TypeInt,
40+
Optional: true,
41+
Default: 1,
42+
},
43+
"project_id": account.ProjectIDSchema(),
44+
45+
"owner_contact_id": {
46+
Type: schema.TypeString,
47+
Optional: true,
48+
},
49+
"owner_contact": {
50+
Type: schema.TypeMap,
51+
Optional: true,
52+
Elem: &schema.Resource{
53+
Schema: contactSchema(),
54+
},
55+
},
56+
"administrative_contact_id": {
57+
Type: schema.TypeString,
58+
Optional: true,
59+
},
60+
"administrative_contact": {
61+
Type: schema.TypeMap,
62+
Optional: true,
63+
Elem: &schema.Resource{
64+
Schema: contactSchema(),
65+
},
66+
},
67+
"technical_contact_id": {
68+
Type: schema.TypeString,
69+
Optional: true,
70+
},
71+
"technical_contact": {
72+
Type: schema.TypeMap,
73+
Optional: true,
74+
Elem: &schema.Resource{
75+
Schema: contactSchema(),
76+
},
77+
},
78+
},
79+
}
80+
}
81+
82+
func contactSchema() map[string]*schema.Schema {
83+
return map[string]*schema.Schema{
84+
"legal_form": {
85+
Type: schema.TypeString,
86+
Required: true,
87+
Description: "Legal form of the contact (e.g., 'individual' or 'organization').",
88+
},
89+
"firstname": {
90+
Type: schema.TypeString,
91+
Required: true,
92+
},
93+
"lastname": {
94+
Type: schema.TypeString,
95+
Required: true,
96+
},
97+
"company_name": {
98+
Type: schema.TypeString,
99+
Optional: true,
100+
},
101+
"email": {
102+
Type: schema.TypeString,
103+
Required: true,
104+
},
105+
"email_alt": {
106+
Type: schema.TypeString,
107+
Optional: true,
108+
},
109+
"phone_number": {
110+
Type: schema.TypeString,
111+
Required: true,
112+
},
113+
"fax_number": {
114+
Type: schema.TypeString,
115+
Optional: true,
116+
},
117+
"address_line_1": {
118+
Type: schema.TypeString,
119+
Required: true,
120+
},
121+
"address_line_2": {
122+
Type: schema.TypeString,
123+
Optional: true,
124+
},
125+
"zip": {
126+
Type: schema.TypeString,
127+
Required: true,
128+
},
129+
"city": {
130+
Type: schema.TypeString,
131+
Required: true,
132+
},
133+
"country": {
134+
Type: schema.TypeString,
135+
Required: true,
136+
},
137+
"vat_identification_code": {
138+
Type: schema.TypeString,
139+
Optional: true,
140+
},
141+
"company_identification_code": {
142+
Type: schema.TypeString,
143+
Optional: true,
144+
},
145+
"lang": {
146+
Type: schema.TypeString,
147+
Optional: true,
148+
},
149+
"resale": {
150+
Type: schema.TypeBool,
151+
Optional: true,
152+
},
153+
"questions": {
154+
Type: schema.TypeList,
155+
Optional: true,
156+
Elem: &schema.Resource{
157+
Schema: map[string]*schema.Schema{
158+
"question": {
159+
Type: schema.TypeString,
160+
Required: true,
161+
},
162+
"answer": {
163+
Type: schema.TypeString,
164+
Required: true,
165+
},
166+
},
167+
},
168+
},
169+
"extension_fr": {
170+
Type: schema.TypeMap,
171+
Optional: true,
172+
Elem: &schema.Schema{
173+
Type: schema.TypeString,
174+
},
175+
},
176+
"extension_eu": {
177+
Type: schema.TypeMap,
178+
Optional: true,
179+
Elem: &schema.Schema{
180+
Type: schema.TypeString,
181+
},
182+
},
183+
"whois_opt_in": {
184+
Type: schema.TypeBool,
185+
Optional: true,
186+
},
187+
"state": {
188+
Type: schema.TypeString,
189+
Optional: true,
190+
},
191+
"extension_nl": {
192+
Type: schema.TypeMap,
193+
Optional: true,
194+
Elem: &schema.Schema{
195+
Type: schema.TypeString,
196+
},
197+
},
198+
}
199+
}
200+
201+
func resourceDomainCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
202+
registrarAPI := NewRegistrarDomainAPI(m)
203+
204+
projectID := d.Get("project_id").(string)
205+
domainNamesInterface := d.Get("domain_names").([]interface{})
206+
domains := make([]string, len(domainNamesInterface))
207+
for i, v := range domainNamesInterface {
208+
domains[i] = v.(string)
209+
}
210+
durationInYears := uint32(d.Get("duration_in_years").(int))
211+
212+
buyDomainsRequest := &domain.RegistrarAPIBuyDomainsRequest{
213+
Domains: domains,
214+
DurationInYears: durationInYears,
215+
ProjectID: projectID,
216+
}
217+
218+
ownerContactID := d.Get("owner_contact_id").(string)
219+
if ownerContactID != "" {
220+
221+
buyDomainsRequest.OwnerContactID = &ownerContactID
222+
} else if ownerContact, ok := d.GetOk("owner_contact"); ok {
223+
buyDomainsRequest.OwnerContact = expandContact(ownerContact.(map[string]interface{}))
224+
}
225+
226+
adminContactID := d.Get("administrative_contact_id").(string)
227+
if adminContactID != "" {
228+
buyDomainsRequest.AdministrativeContactID = &adminContactID
229+
} else if adminContact, ok := d.GetOk("administrative_contact"); ok {
230+
buyDomainsRequest.AdministrativeContact = expandContact(adminContact.(map[string]interface{}))
231+
}
232+
233+
techContactID := d.Get("technical_contact_id").(string)
234+
if adminContactID != "" {
235+
buyDomainsRequest.TechnicalContactID = &techContactID
236+
} else if techContact, ok := d.GetOk("technical_contact"); ok {
237+
buyDomainsRequest.TechnicalContact = expandContact(techContact.(map[string]interface{}))
238+
}
239+
240+
resp, err := registrarAPI.BuyDomains(buyDomainsRequest, scw.WithContext(ctx))
241+
if err != nil {
242+
return diag.FromErr(err)
243+
}
244+
245+
d.SetId(resp.ProjectID + "/" + resp.TaskID)
246+
247+
return resourceDomainsRead(ctx, d, m)
248+
}
249+
250+
func resourceDomainsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
251+
registrarAPI := NewRegistrarDomainAPI(m)
252+
253+
}
254+
255+
func contactToMap(contact *domain.Contact) map[string]interface{} {
256+
if contact == nil {
257+
return nil
258+
}
259+
return map[string]interface{}{
260+
"id": contact.ID,
261+
"firstname": contact.Firstname,
262+
"lastname": contact.Lastname,
263+
"email": contact.Email,
264+
}
265+
}
266+
267+
func fetchAllDomains(ctx context.Context, registrarAPI *domain.RegistrarAPI, projectID string) ([]*domain.DomainSummary, error) {
268+
var allDomains []*domain.DomainSummary
269+
270+
page := int32(1)
271+
pageSize := uint32(1000)
272+
273+
for {
274+
listDomainsRequest := &domain.RegistrarAPIListDomainsRequest{
275+
ProjectID: &projectID,
276+
Page: &page,
277+
PageSize: &pageSize,
278+
}
279+
280+
domainsResponse, err := registrarAPI.ListDomains(listDomainsRequest, scw.WithContext(ctx))
281+
if err != nil {
282+
return nil, err
283+
}
284+
285+
allDomains = append(allDomains, domainsResponse.Domains...)
286+
287+
if len(domainsResponse.Domains) < int(pageSize) {
288+
break
289+
}
290+
page++
291+
}
292+
293+
return allDomains, nil
294+
}

internal/services/domain/helpers.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ func NewDomainAPI(m interface{}) *domain.API {
1414
return domain.NewAPI(meta.ExtractScwClient(m))
1515
}
1616

17+
func NewRegistrarDomainAPI(m interface{}) *domain.RegistrarAPI {
18+
return domain.NewRegistrarAPI(meta.ExtractScwClient(m))
19+
}
20+
1721
func getRecordFromTypeAndData(dnsType domain.RecordType, data string, records []*domain.Record) (*domain.Record, error) {
1822
var currentRecord *domain.Record
1923
for _, r := range records {

0 commit comments

Comments
 (0)