From 9f314a3c29944885a9d61e54eb62e363d9a64c23 Mon Sep 17 00:00:00 2001 From: Raphael Randschau Date: Mon, 25 Jul 2016 13:49:09 +0200 Subject: [PATCH] provider/scaleway: Expose IPv6 support, improve documentation (#7784) * provider/scaleway: update api version * provider/scaleway: expose ipv6 support, rename ip attributes since it can be both ipv4 and ipv6, choose a more generic name. * provider/scaleway: allow servers in different SGs * provider/scaleway: update documentation * provider/scaleway: Update docs with security group * provider/scaleway: add testcase for server security groups * provider/scaleway: make deleting of security rules more resilient * provider/scaleway: make deletion of security group more resilient * provider/scaleway: guard against missing server --- .../scaleway/resource_scaleway_ip.go | 4 +- .../scaleway/resource_scaleway_ip_test.go | 6 +- .../resource_scaleway_security_group.go | 11 +- .../resource_scaleway_security_group_rule.go | 9 + .../scaleway/resource_scaleway_server.go | 44 +++- .../scaleway/resource_scaleway_server_test.go | 86 +++++++ .../scaleway/scaleway-cli/pkg/api/api.go | 132 +++++++---- .../scaleway/scaleway-cli/pkg/api/cache.go | 212 ++++++++++++------ .../scaleway/scaleway-cli/pkg/api/logger.go | 30 ++- .../providers/scaleway/r/server.html.markdown | 9 +- 10 files changed, 417 insertions(+), 126 deletions(-) diff --git a/builtin/providers/scaleway/resource_scaleway_ip.go b/builtin/providers/scaleway/resource_scaleway_ip.go index b4fe7003f..100930a33 100644 --- a/builtin/providers/scaleway/resource_scaleway_ip.go +++ b/builtin/providers/scaleway/resource_scaleway_ip.go @@ -54,7 +54,9 @@ func resourceScalewayIPRead(d *schema.ResourceData, m interface{}) error { } d.Set("ip", resp.IP.Address) - d.Set("server", resp.IP.Server.Identifier) + if resp.IP.Server != nil { + d.Set("server", resp.IP.Server.Identifier) + } return nil } diff --git a/builtin/providers/scaleway/resource_scaleway_ip_test.go b/builtin/providers/scaleway/resource_scaleway_ip_test.go index 464817eff..f32cae1f5 100644 --- a/builtin/providers/scaleway/resource_scaleway_ip_test.go +++ b/builtin/providers/scaleway/resource_scaleway_ip_test.go @@ -112,7 +112,11 @@ func testAccCheckScalewayIPAttachment(n string, check func(string) bool, msg str return err } - if !check(ip.IP.Server.Identifier) { + var serverID = "" + if ip.IP.Server != nil { + serverID = ip.IP.Server.Identifier + } + if !check(serverID) { return fmt.Errorf("IP check failed: %q", msg) } diff --git a/builtin/providers/scaleway/resource_scaleway_security_group.go b/builtin/providers/scaleway/resource_scaleway_security_group.go index 6c5da13d6..a3421dee8 100644 --- a/builtin/providers/scaleway/resource_scaleway_security_group.go +++ b/builtin/providers/scaleway/resource_scaleway_security_group.go @@ -90,7 +90,7 @@ func resourceScalewaySecurityGroupRead(d *schema.ResourceData, m interface{}) er func resourceScalewaySecurityGroupUpdate(d *schema.ResourceData, m interface{}) error { scaleway := m.(*Client).scaleway - var req = api.ScalewayNewSecurityGroup{ + var req = api.ScalewayUpdateSecurityGroup{ Organization: scaleway.Organization, Name: d.Get("name").(string), Description: d.Get("description").(string), @@ -110,6 +110,15 @@ func resourceScalewaySecurityGroupDelete(d *schema.ResourceData, m interface{}) err := scaleway.DeleteSecurityGroup(d.Id()) if err != nil { + if serr, ok := err.(api.ScalewayAPIError); ok { + log.Printf("[DEBUG] error reading Security Group Rule: %q\n", serr.APIMessage) + + if serr.StatusCode == 404 { + d.SetId("") + return nil + } + } + return err } diff --git a/builtin/providers/scaleway/resource_scaleway_security_group_rule.go b/builtin/providers/scaleway/resource_scaleway_security_group_rule.go index 85c2f3575..d79070bfe 100644 --- a/builtin/providers/scaleway/resource_scaleway_security_group_rule.go +++ b/builtin/providers/scaleway/resource_scaleway_security_group_rule.go @@ -154,6 +154,15 @@ func resourceScalewaySecurityGroupRuleDelete(d *schema.ResourceData, m interface err := scaleway.DeleteSecurityGroupRule(d.Get("security_group").(string), d.Id()) if err != nil { + if serr, ok := err.(api.ScalewayAPIError); ok { + log.Printf("[DEBUG] error reading Security Group Rule: %q\n", serr.APIMessage) + + if serr.StatusCode == 404 { + d.SetId("") + return nil + } + } + return err } diff --git a/builtin/providers/scaleway/resource_scaleway_server.go b/builtin/providers/scaleway/resource_scaleway_server.go index 659c5c29f..0266fcc9d 100644 --- a/builtin/providers/scaleway/resource_scaleway_server.go +++ b/builtin/providers/scaleway/resource_scaleway_server.go @@ -40,11 +40,24 @@ func resourceScalewayServer() *schema.Resource { }, Optional: true, }, - "ipv4_address_private": &schema.Schema{ + "enable_ipv6": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "dynamic_ip_required": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + }, + "security_group": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "private_ip": &schema.Schema{ Type: schema.TypeString, Computed: true, }, - "ipv4_address_public": &schema.Schema{ + "public_ip": &schema.Schema{ Type: schema.TypeString, Computed: true, }, @@ -53,10 +66,6 @@ func resourceScalewayServer() *schema.Resource { Optional: true, Computed: true, }, - "dynamic_ip_required": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - }, "state_detail": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -70,9 +79,11 @@ func resourceScalewayServerCreate(d *schema.ResourceData, m interface{}) error { image := d.Get("image").(string) var server = api.ScalewayServerDefinition{ - Name: d.Get("name").(string), - Image: String(image), - Organization: scaleway.Organization, + Name: d.Get("name").(string), + Image: String(image), + Organization: scaleway.Organization, + EnableIPV6: d.Get("enable_ipv6").(bool), + SecurityGroup: d.Get("security_group").(string), } server.DynamicIPRequired = Bool(d.Get("dynamic_ip_required").(bool)) @@ -127,8 +138,9 @@ func resourceScalewayServerRead(d *schema.ResourceData, m interface{}) error { return err } - d.Set("ipv4_address_private", server.PrivateIP) - d.Set("ipv4_address_public", server.PublicAddress.IP) + d.Set("private_ip", server.PrivateIP) + d.Set("public_ip", server.PublicAddress.IP) + d.Set("state", server.State) d.Set("state_detail", server.StateDetail) d.Set("tags", server.Tags) @@ -161,10 +173,20 @@ func resourceScalewayServerUpdate(d *schema.ResourceData, m interface{}) error { } } + if d.HasChange("enable_ipv6") { + req.EnableIPV6 = Bool(d.Get("enable_ipv6").(bool)) + } + if d.HasChange("dynamic_ip_required") { req.DynamicIPRequired = Bool(d.Get("dynamic_ip_required").(bool)) } + if d.HasChange("security_group") { + req.SecurityGroup = &api.ScalewaySecurityGroup{ + Identifier: d.Get("security_group").(string), + } + } + if err := scaleway.PatchServer(d.Id(), req); err != nil { return fmt.Errorf("Failed patching scaleway server: %q", err) } diff --git a/builtin/providers/scaleway/resource_scaleway_server_test.go b/builtin/providers/scaleway/resource_scaleway_server_test.go index 27fdab537..a9ef42727 100644 --- a/builtin/providers/scaleway/resource_scaleway_server_test.go +++ b/builtin/providers/scaleway/resource_scaleway_server_test.go @@ -31,6 +31,30 @@ func TestAccScalewayServer_Basic(t *testing.T) { }) } +func TestAccScalewayServer_SecurityGroup(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckScalewayServerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckScalewayServerConfig_SecurityGroup, + Check: resource.ComposeTestCheckFunc( + testAccCheckScalewayServerExists("scaleway_server.base"), + testAccCheckScalewayServerSecurityGroup("scaleway_server.base", "blue"), + ), + }, + resource.TestStep{ + Config: testAccCheckScalewayServerConfig_SecurityGroup_Update, + Check: resource.ComposeTestCheckFunc( + testAccCheckScalewayServerExists("scaleway_server.base"), + testAccCheckScalewayServerSecurityGroup("scaleway_server.base", "red"), + ), + }, + }, + }) +} + func testAccCheckScalewayServerDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*Client).scaleway @@ -77,6 +101,28 @@ func testAccCheckScalewayServerAttributes(n string) resource.TestCheckFunc { } } +func testAccCheckScalewayServerSecurityGroup(n, securityGroupName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Unknown resource: %s", n) + } + + client := testAccProvider.Meta().(*Client).scaleway + server, err := client.GetServer(rs.Primary.ID) + + if err != nil { + return err + } + + if server.SecurityGroup.Name != securityGroupName { + return fmt.Errorf("Server has wrong security_group") + } + + return nil + } +} + func testAccCheckScalewayServerExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -114,3 +160,43 @@ resource "scaleway_server" "base" { type = "C1" tags = [ "terraform-test" ] }`, armImageIdentifier) + +var testAccCheckScalewayServerConfig_SecurityGroup = fmt.Sprintf(` +resource "scaleway_security_group" "blue" { + name = "blue" + description = "blue" +} + +resource "scaleway_security_group" "red" { + name = "red" + description = "red" +} + +resource "scaleway_server" "base" { + name = "test" + # ubuntu 14.04 + image = "%s" + type = "C1" + tags = [ "terraform-test" ] + security_group = "${scaleway_security_group.blue.id}" +}`, armImageIdentifier) + +var testAccCheckScalewayServerConfig_SecurityGroup_Update = fmt.Sprintf(` +resource "scaleway_security_group" "blue" { + name = "blue" + description = "blue" +} + +resource "scaleway_security_group" "red" { + name = "red" + description = "red" +} + +resource "scaleway_server" "base" { + name = "test" + # ubuntu 14.04 + image = "%s" + type = "C1" + tags = [ "terraform-test" ] + security_group = "${scaleway_security_group.red.id}" +}`, armImageIdentifier) diff --git a/vendor/github.com/scaleway/scaleway-cli/pkg/api/api.go b/vendor/github.com/scaleway/scaleway-cli/pkg/api/api.go index cd3a81e28..976d28564 100644 --- a/vendor/github.com/scaleway/scaleway-cli/pkg/api/api.go +++ b/vendor/github.com/scaleway/scaleway-cli/pkg/api/api.go @@ -98,7 +98,7 @@ func (e ScalewayAPIError) Error() string { "Message": e.Message, "APIMessage": e.APIMessage, } { - fmt.Fprintf(&b, " %-30s %s", fmt.Sprintf("%s: ", k), v) + fmt.Fprintf(&b, "%s: %v ", k, v) } return b.String() } @@ -419,13 +419,13 @@ type ScalewayGetSecurityGroup struct { // ScalewayIPDefinition represents the IP's fields type ScalewayIPDefinition struct { - Organization string `json:"organization"` - Reverse string `json:"reverse"` - ID string `json:"id"` - Server struct { + Organization string `json:"organization"` + Reverse *string `json:"reverse"` + ID string `json:"id"` + Server *struct { Identifier string `json:"id,omitempty"` Name string `json:"name,omitempty"` - } `json:"server,omitempty"` + } `json:"server"` Address string `json:"address"` } @@ -448,11 +448,20 @@ type ScalewaySecurityGroup struct { Name string `json:"name,omitempty"` } -// ScalewayNewSecurityGroup definition POST/PUT request /security_groups +// ScalewayNewSecurityGroup definition POST request /security_groups type ScalewayNewSecurityGroup struct { - Organization string `json:"organization"` - Name string `json:"name"` - Description string `json:"description"` + Organization string `json:"organization"` + Name string `json:"name"` + Description string `json:"description"` + OrganizationDefault bool `json:"organization_default"` +} + +// ScalewayUpdateSecurityGroup definition PUT request /security_groups +type ScalewayUpdateSecurityGroup struct { + Organization string `json:"organization"` + Name string `json:"name"` + Description string `json:"description"` + OrganizationDefault bool `json:"organization_default"` } // ScalewayServer represents a Scaleway server @@ -584,6 +593,8 @@ type ScalewayServerDefinition struct { PublicIP string `json:"public_ip,omitempty"` EnableIPV6 bool `json:"enable_ipv6,omitempty"` + + SecurityGroup string `json:"security_group,omitempty"` } // ScalewayOneServer represents the response of a GET /servers/UUID API call @@ -832,27 +843,26 @@ type MarketImages struct { // NewScalewayAPI creates a ready-to-use ScalewayAPI client func NewScalewayAPI(organization, token, userAgent string, options ...func(*ScalewayAPI)) (*ScalewayAPI, error) { - cache, err := NewScalewayCache() - if err != nil { - return nil, err - } s := &ScalewayAPI{ // exposed Organization: organization, Token: token, - Cache: cache, Logger: NewDefaultLogger(), - verbose: os.Getenv("SCW_VERBOSE_API") != "", - password: "", - userAgent: userAgent, // internal - client: &http.Client{}, + client: &http.Client{}, + verbose: os.Getenv("SCW_VERBOSE_API") != "", + password: "", + userAgent: userAgent, } for _, option := range options { option(s) } - + cache, err := NewScalewayCache(func() { s.Logger.Debugf("Writing cache file to disk") }) + if err != nil { + return nil, err + } + s.Cache = cache if os.Getenv("SCW_TLSVERIFY") == "0" { s.client.Transport = &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, @@ -1273,62 +1283,77 @@ func (s *ScalewayAPI) PutVolume(volumeID string, definition ScalewayVolumePutDef // ResolveServer attempts to find a matching Identifier for the input string func (s *ScalewayAPI) ResolveServer(needle string) (ScalewayResolverResults, error) { - servers := s.Cache.LookUpServers(needle, true) + servers, err := s.Cache.LookUpServers(needle, true) + if err != nil { + return servers, err + } if len(servers) == 0 { - if _, err := s.GetServers(true, 0); err != nil { + if _, err = s.GetServers(true, 0); err != nil { return nil, err } - servers = s.Cache.LookUpServers(needle, true) + servers, err = s.Cache.LookUpServers(needle, true) } - return servers, nil + return servers, err } // ResolveVolume attempts to find a matching Identifier for the input string func (s *ScalewayAPI) ResolveVolume(needle string) (ScalewayResolverResults, error) { - volumes := s.Cache.LookUpVolumes(needle, true) + volumes, err := s.Cache.LookUpVolumes(needle, true) + if err != nil { + return volumes, err + } if len(volumes) == 0 { - if _, err := s.GetVolumes(); err != nil { + if _, err = s.GetVolumes(); err != nil { return nil, err } - volumes = s.Cache.LookUpVolumes(needle, true) + volumes, err = s.Cache.LookUpVolumes(needle, true) } - return volumes, nil + return volumes, err } // ResolveSnapshot attempts to find a matching Identifier for the input string func (s *ScalewayAPI) ResolveSnapshot(needle string) (ScalewayResolverResults, error) { - snapshots := s.Cache.LookUpSnapshots(needle, true) + snapshots, err := s.Cache.LookUpSnapshots(needle, true) + if err != nil { + return snapshots, err + } if len(snapshots) == 0 { - if _, err := s.GetSnapshots(); err != nil { + if _, err = s.GetSnapshots(); err != nil { return nil, err } - snapshots = s.Cache.LookUpSnapshots(needle, true) + snapshots, err = s.Cache.LookUpSnapshots(needle, true) } - return snapshots, nil + return snapshots, err } // ResolveImage attempts to find a matching Identifier for the input string func (s *ScalewayAPI) ResolveImage(needle string) (ScalewayResolverResults, error) { - images := s.Cache.LookUpImages(needle, true) + images, err := s.Cache.LookUpImages(needle, true) + if err != nil { + return images, err + } if len(images) == 0 { - if _, err := s.GetImages(); err != nil { + if _, err = s.GetImages(); err != nil { return nil, err } - images = s.Cache.LookUpImages(needle, true) + images, err = s.Cache.LookUpImages(needle, true) } - return images, nil + return images, err } // ResolveBootscript attempts to find a matching Identifier for the input string func (s *ScalewayAPI) ResolveBootscript(needle string) (ScalewayResolverResults, error) { - bootscripts := s.Cache.LookUpBootscripts(needle, true) + bootscripts, err := s.Cache.LookUpBootscripts(needle, true) + if err != nil { + return bootscripts, err + } if len(bootscripts) == 0 { - if _, err := s.GetBootscripts(); err != nil { + if _, err = s.GetBootscripts(); err != nil { return nil, err } - bootscripts = s.Cache.LookUpBootscripts(needle, true) + bootscripts, err = s.Cache.LookUpBootscripts(needle, true) } - return bootscripts, nil + return bootscripts, err } // GetImages gets the list of images from the ScalewayAPI @@ -2154,7 +2179,7 @@ func (s *ScalewayAPI) DeleteSecurityGroup(securityGroupID string) error { } // PutSecurityGroup updates a SecurityGroup -func (s *ScalewayAPI) PutSecurityGroup(group ScalewayNewSecurityGroup, securityGroupID string) error { +func (s *ScalewayAPI) PutSecurityGroup(group ScalewayUpdateSecurityGroup, securityGroupID string) error { resp, err := s.PutResponse(ComputeAPI, fmt.Sprintf("security_groups/%s", securityGroupID), group) if resp != nil { defer resp.Body.Close() @@ -2313,6 +2338,24 @@ func (s *ScalewayAPI) AttachIP(ipID, serverID string) error { return err } +// DetachIP detaches an IP from a server +func (s *ScalewayAPI) DetachIP(ipID string) error { + ip, err := s.GetIP(ipID) + if err != nil { + return err + } + ip.IP.Server = nil + resp, err := s.PutResponse(ComputeAPI, fmt.Sprintf("ips/%s", ipID), ip.IP) + if resp != nil { + defer resp.Body.Close() + } + if err != nil { + return err + } + _, err = s.handleHTTPError([]int{200}, resp) + return err +} + // DeleteIP deletes an IP func (s *ScalewayAPI) DeleteIP(ipID string) error { resp, err := s.DeleteResponse(ComputeAPI, fmt.Sprintf("ips/%s", ipID)) @@ -2322,11 +2365,8 @@ func (s *ScalewayAPI) DeleteIP(ipID string) error { if err != nil { return err } - - if _, err := s.handleHTTPError([]int{204}, resp); err != nil { - return err - } - return nil + _, err = s.handleHTTPError([]int{204}, resp) + return err } // GetIP returns a ScalewayGetIP diff --git a/vendor/github.com/scaleway/scaleway-cli/pkg/api/cache.go b/vendor/github.com/scaleway/scaleway-cli/pkg/api/cache.go index 72d119059..529bdaaf2 100644 --- a/vendor/github.com/scaleway/scaleway-cli/pkg/api/cache.go +++ b/vendor/github.com/scaleway/scaleway-cli/pkg/api/cache.go @@ -8,7 +8,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "log" "os" "path/filepath" "regexp" @@ -60,6 +59,8 @@ type ScalewayCache struct { // Lock allows ScalewayCache to be used concurrently Lock sync.Mutex `json:"-"` + + hookSave func() } const ( @@ -92,16 +93,16 @@ type ScalewayResolverResult struct { type ScalewayResolverResults []ScalewayResolverResult // NewScalewayResolverResult returns a new ScalewayResolverResult -func NewScalewayResolverResult(Identifier, Name, Arch string, Type int) ScalewayResolverResult { +func NewScalewayResolverResult(Identifier, Name, Arch string, Type int) (ScalewayResolverResult, error) { if err := anonuuid.IsUUID(Identifier); err != nil { - log.Fatal(err) + return ScalewayResolverResult{}, err } return ScalewayResolverResult{ Identifier: Identifier, Type: Type, Name: Name, Arch: Arch, - } + }, nil } func (s ScalewayResolverResults) Len() int { @@ -160,7 +161,10 @@ REDO: } // NewScalewayCache loads a per-user cache -func NewScalewayCache() (*ScalewayCache, error) { +func NewScalewayCache(hookSave func()) (*ScalewayCache, error) { + var cache ScalewayCache + + cache.hookSave = hookSave homeDir := os.Getenv("HOME") // *nix if homeDir == "" { // Windows homeDir = os.Getenv("USERPROFILE") @@ -169,7 +173,6 @@ func NewScalewayCache() (*ScalewayCache, error) { homeDir = "/tmp" } cachePath := filepath.Join(homeDir, ".scw-cache.db") - var cache ScalewayCache cache.Path = cachePath _, err := os.Stat(cachePath) if os.IsNotExist(err) { @@ -210,13 +213,13 @@ func NewScalewayCache() (*ScalewayCache, error) { } // Clear removes all information from the cache -func (s *ScalewayCache) Clear() { - s.Images = make(map[string][CacheMaxfield]string) - s.Snapshots = make(map[string][CacheMaxfield]string) - s.Volumes = make(map[string][CacheMaxfield]string) - s.Bootscripts = make(map[string][CacheMaxfield]string) - s.Servers = make(map[string][CacheMaxfield]string) - s.Modified = true +func (c *ScalewayCache) Clear() { + c.Images = make(map[string][CacheMaxfield]string) + c.Snapshots = make(map[string][CacheMaxfield]string) + c.Volumes = make(map[string][CacheMaxfield]string) + c.Bootscripts = make(map[string][CacheMaxfield]string) + c.Servers = make(map[string][CacheMaxfield]string) + c.Modified = true } // Flush flushes the cache database @@ -229,8 +232,7 @@ func (c *ScalewayCache) Save() error { c.Lock.Lock() defer c.Lock.Unlock() - log.Printf("Writing cache file to disk") - + c.hookSave() if c.Modified { file, err := ioutil.TempFile(filepath.Dir(c.Path), filepath.Base(c.Path)) if err != nil { @@ -259,15 +261,19 @@ func (s *ScalewayResolverResult) ComputeRankMatch(needle string) { } // LookUpImages attempts to return identifiers matching a pattern -func (c *ScalewayCache) LookUpImages(needle string, acceptUUID bool) ScalewayResolverResults { +func (c *ScalewayCache) LookUpImages(needle string, acceptUUID bool) (ScalewayResolverResults, error) { c.Lock.Lock() defer c.Lock.Unlock() var res ScalewayResolverResults + var exactMatches ScalewayResolverResults if acceptUUID && anonuuid.IsUUID(needle) == nil { if fields, ok := c.Images[needle]; ok { - entry := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierImage) + entry, err := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierImage) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } @@ -276,41 +282,53 @@ func (c *ScalewayCache) LookUpImages(needle string, acceptUUID bool) ScalewayRes needle = regexp.MustCompile(`^user/`).ReplaceAllString(needle, "") // FIXME: if 'user/' is in needle, only watch for a user image nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*")) - var exactMatches ScalewayResolverResults for identifier, fields := range c.Images { if fields[CacheTitle] == needle { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) exactMatches = append(exactMatches, entry) } if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } else if strings.HasPrefix(fields[CacheMarketPlaceUUID], needle) || nameRegex.MatchString(fields[CacheMarketPlaceUUID]) { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } if len(exactMatches) == 1 { - return exactMatches + return exactMatches, nil } - return removeDuplicatesResults(res) + return removeDuplicatesResults(res), nil } // LookUpSnapshots attempts to return identifiers matching a pattern -func (c *ScalewayCache) LookUpSnapshots(needle string, acceptUUID bool) ScalewayResolverResults { +func (c *ScalewayCache) LookUpSnapshots(needle string, acceptUUID bool) (ScalewayResolverResults, error) { c.Lock.Lock() defer c.Lock.Unlock() var res ScalewayResolverResults + var exactMatches ScalewayResolverResults if acceptUUID && anonuuid.IsUUID(needle) == nil { if fields, ok := c.Snapshots[needle]; ok { - entry := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierSnapshot) + entry, err := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierSnapshot) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } @@ -318,136 +336,168 @@ func (c *ScalewayCache) LookUpSnapshots(needle string, acceptUUID bool) Scaleway needle = regexp.MustCompile(`^user/`).ReplaceAllString(needle, "") nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*")) - var exactMatches ScalewayResolverResults for identifier, fields := range c.Snapshots { if fields[CacheTitle] == needle { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierSnapshot) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierSnapshot) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) exactMatches = append(exactMatches, entry) } if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierSnapshot) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierSnapshot) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } if len(exactMatches) == 1 { - return exactMatches + return exactMatches, nil } - return removeDuplicatesResults(res) + return removeDuplicatesResults(res), nil } // LookUpVolumes attempts to return identifiers matching a pattern -func (c *ScalewayCache) LookUpVolumes(needle string, acceptUUID bool) ScalewayResolverResults { +func (c *ScalewayCache) LookUpVolumes(needle string, acceptUUID bool) (ScalewayResolverResults, error) { c.Lock.Lock() defer c.Lock.Unlock() var res ScalewayResolverResults + var exactMatches ScalewayResolverResults if acceptUUID && anonuuid.IsUUID(needle) == nil { if fields, ok := c.Volumes[needle]; ok { - entry := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierVolume) + entry, err := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierVolume) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*")) - var exactMatches ScalewayResolverResults for identifier, fields := range c.Volumes { if fields[CacheTitle] == needle { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierVolume) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierVolume) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) exactMatches = append(exactMatches, entry) } if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierVolume) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierVolume) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } if len(exactMatches) == 1 { - return exactMatches + return exactMatches, nil } - return removeDuplicatesResults(res) + return removeDuplicatesResults(res), nil } // LookUpBootscripts attempts to return identifiers matching a pattern -func (c *ScalewayCache) LookUpBootscripts(needle string, acceptUUID bool) ScalewayResolverResults { +func (c *ScalewayCache) LookUpBootscripts(needle string, acceptUUID bool) (ScalewayResolverResults, error) { c.Lock.Lock() defer c.Lock.Unlock() var res ScalewayResolverResults + var exactMatches ScalewayResolverResults if acceptUUID && anonuuid.IsUUID(needle) == nil { if fields, ok := c.Bootscripts[needle]; ok { - entry := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierBootscript) + entry, err := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierBootscript) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*")) - var exactMatches ScalewayResolverResults for identifier, fields := range c.Bootscripts { if fields[CacheTitle] == needle { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierBootscript) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierBootscript) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) exactMatches = append(exactMatches, entry) } if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierBootscript) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierBootscript) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } if len(exactMatches) == 1 { - return exactMatches + return exactMatches, nil } - return removeDuplicatesResults(res) + return removeDuplicatesResults(res), nil } // LookUpServers attempts to return identifiers matching a pattern -func (c *ScalewayCache) LookUpServers(needle string, acceptUUID bool) ScalewayResolverResults { +func (c *ScalewayCache) LookUpServers(needle string, acceptUUID bool) (ScalewayResolverResults, error) { c.Lock.Lock() defer c.Lock.Unlock() var res ScalewayResolverResults + var exactMatches ScalewayResolverResults if acceptUUID && anonuuid.IsUUID(needle) == nil { if fields, ok := c.Servers[needle]; ok { - entry := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierServer) + entry, err := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierServer) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*")) - var exactMatches ScalewayResolverResults for identifier, fields := range c.Servers { if fields[CacheTitle] == needle { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierServer) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierServer) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) exactMatches = append(exactMatches, entry) } if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) { - entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierServer) + entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierServer) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) res = append(res, entry) } } if len(exactMatches) == 1 { - return exactMatches + return exactMatches, nil } - return removeDuplicatesResults(res) + return removeDuplicatesResults(res), nil } // removeDuplicatesResults transforms an array into a unique array @@ -492,52 +542,86 @@ func parseNeedle(input string) (identifierType int, needle string) { } // LookUpIdentifiers attempts to return identifiers matching a pattern -func (c *ScalewayCache) LookUpIdentifiers(needle string) ScalewayResolverResults { +func (c *ScalewayCache) LookUpIdentifiers(needle string) (ScalewayResolverResults, error) { results := ScalewayResolverResults{} identifierType, needle := parseNeedle(needle) if identifierType&(IdentifierUnknown|IdentifierServer) > 0 { - for _, result := range c.LookUpServers(needle, false) { - entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierServer) + servers, err := c.LookUpServers(needle, false) + if err != nil { + return ScalewayResolverResults{}, err + } + for _, result := range servers { + entry, err := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierServer) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) results = append(results, entry) } } if identifierType&(IdentifierUnknown|IdentifierImage) > 0 { - for _, result := range c.LookUpImages(needle, false) { - entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierImage) + images, err := c.LookUpImages(needle, false) + if err != nil { + return ScalewayResolverResults{}, err + } + for _, result := range images { + entry, err := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierImage) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) results = append(results, entry) } } if identifierType&(IdentifierUnknown|IdentifierSnapshot) > 0 { - for _, result := range c.LookUpSnapshots(needle, false) { - entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierSnapshot) + snapshots, err := c.LookUpSnapshots(needle, false) + if err != nil { + return ScalewayResolverResults{}, err + } + for _, result := range snapshots { + entry, err := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierSnapshot) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) results = append(results, entry) } } if identifierType&(IdentifierUnknown|IdentifierVolume) > 0 { - for _, result := range c.LookUpVolumes(needle, false) { - entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierVolume) + volumes, err := c.LookUpVolumes(needle, false) + if err != nil { + return ScalewayResolverResults{}, err + } + for _, result := range volumes { + entry, err := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierVolume) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) results = append(results, entry) } } if identifierType&(IdentifierUnknown|IdentifierBootscript) > 0 { - for _, result := range c.LookUpBootscripts(needle, false) { - entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierBootscript) + bootscripts, err := c.LookUpBootscripts(needle, false) + if err != nil { + return ScalewayResolverResults{}, err + } + for _, result := range bootscripts { + entry, err := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierBootscript) + if err != nil { + return ScalewayResolverResults{}, err + } entry.ComputeRankMatch(needle) results = append(results, entry) } } - - return results + return results, nil } // InsertServer registers a server in the cache diff --git a/vendor/github.com/scaleway/scaleway-cli/pkg/api/logger.go b/vendor/github.com/scaleway/scaleway-cli/pkg/api/logger.go index d14a59dcb..58ad93716 100644 --- a/vendor/github.com/scaleway/scaleway-cli/pkg/api/logger.go +++ b/vendor/github.com/scaleway/scaleway-cli/pkg/api/logger.go @@ -32,18 +32,46 @@ type defaultLogger struct { } func (l *defaultLogger) LogHTTP(r *http.Request) { - l.Printf("%s %s\n", r.Method, r.URL.Path) + l.Printf("%s %s\n", r.Method, r.URL.RawPath) } + func (l *defaultLogger) Fatalf(format string, v ...interface{}) { l.Printf("[FATAL] %s\n", fmt.Sprintf(format, v)) os.Exit(1) } + func (l *defaultLogger) Debugf(format string, v ...interface{}) { l.Printf("[DEBUG] %s\n", fmt.Sprintf(format, v)) } + func (l *defaultLogger) Infof(format string, v ...interface{}) { l.Printf("[INFO ] %s\n", fmt.Sprintf(format, v)) } + func (l *defaultLogger) Warnf(format string, v ...interface{}) { l.Printf("[WARN ] %s\n", fmt.Sprintf(format, v)) } + +type disableLogger struct { +} + +// NewDisableLogger returns a logger which is configured to do nothing +func NewDisableLogger() Logger { + return &disableLogger{} +} + +func (d *disableLogger) LogHTTP(r *http.Request) { +} + +func (d *disableLogger) Fatalf(format string, v ...interface{}) { + panic(fmt.Sprintf(format, v)) +} + +func (d *disableLogger) Debugf(format string, v ...interface{}) { +} + +func (d *disableLogger) Infof(format string, v ...interface{}) { +} + +func (d *disableLogger) Warnf(format string, v ...interface{}) { +} diff --git a/website/source/docs/providers/scaleway/r/server.html.markdown b/website/source/docs/providers/scaleway/r/server.html.markdown index 0d6008bab..d03f70df5 100644 --- a/website/source/docs/providers/scaleway/r/server.html.markdown +++ b/website/source/docs/providers/scaleway/r/server.html.markdown @@ -28,11 +28,18 @@ The following arguments are supported: * `name` - (Required) name of ARM server * `image` - (Required) base image of ARM server * `type` - (Required) type of ARM server +* `bootscript` - (Optional) server bootscript +* `tags` - (Optional) list of tags for server +* `enable_ipv6` - (Optional) enable ipv6 +* `dynamic_ip_required` - (Optional) make server publicly available +* `security_group` - (Optional) assign security group to server -Field `name`, `type` are editable. +Field `name`, `type`, `tags`, `dynamic_ip_required`, `security_group` are editable. ## Attributes Reference The following attributes are exported: * `id` - id of the new resource +* `private_ip` - private ip of the new resource +* `public_ip` - public ip of the new resource