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
This commit is contained in:
parent
f8575f1edd
commit
9f314a3c29
|
@ -54,7 +54,9 @@ func resourceScalewayIPRead(d *schema.ResourceData, m interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Set("ip", resp.IP.Address)
|
d.Set("ip", resp.IP.Address)
|
||||||
|
if resp.IP.Server != nil {
|
||||||
d.Set("server", resp.IP.Server.Identifier)
|
d.Set("server", resp.IP.Server.Identifier)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,11 @@ func testAccCheckScalewayIPAttachment(n string, check func(string) bool, msg str
|
||||||
return err
|
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)
|
return fmt.Errorf("IP check failed: %q", msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ func resourceScalewaySecurityGroupRead(d *schema.ResourceData, m interface{}) er
|
||||||
func resourceScalewaySecurityGroupUpdate(d *schema.ResourceData, m interface{}) error {
|
func resourceScalewaySecurityGroupUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
scaleway := m.(*Client).scaleway
|
scaleway := m.(*Client).scaleway
|
||||||
|
|
||||||
var req = api.ScalewayNewSecurityGroup{
|
var req = api.ScalewayUpdateSecurityGroup{
|
||||||
Organization: scaleway.Organization,
|
Organization: scaleway.Organization,
|
||||||
Name: d.Get("name").(string),
|
Name: d.Get("name").(string),
|
||||||
Description: d.Get("description").(string),
|
Description: d.Get("description").(string),
|
||||||
|
@ -110,6 +110,15 @@ func resourceScalewaySecurityGroupDelete(d *schema.ResourceData, m interface{})
|
||||||
|
|
||||||
err := scaleway.DeleteSecurityGroup(d.Id())
|
err := scaleway.DeleteSecurityGroup(d.Id())
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,15 @@ func resourceScalewaySecurityGroupRuleDelete(d *schema.ResourceData, m interface
|
||||||
|
|
||||||
err := scaleway.DeleteSecurityGroupRule(d.Get("security_group").(string), d.Id())
|
err := scaleway.DeleteSecurityGroupRule(d.Get("security_group").(string), d.Id())
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,24 @@ func resourceScalewayServer() *schema.Resource {
|
||||||
},
|
},
|
||||||
Optional: true,
|
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,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
"ipv4_address_public": &schema.Schema{
|
"public_ip": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
@ -53,10 +66,6 @@ func resourceScalewayServer() *schema.Resource {
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
"dynamic_ip_required": &schema.Schema{
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"state_detail": &schema.Schema{
|
"state_detail": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
|
@ -73,6 +82,8 @@ func resourceScalewayServerCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
Name: d.Get("name").(string),
|
Name: d.Get("name").(string),
|
||||||
Image: String(image),
|
Image: String(image),
|
||||||
Organization: scaleway.Organization,
|
Organization: scaleway.Organization,
|
||||||
|
EnableIPV6: d.Get("enable_ipv6").(bool),
|
||||||
|
SecurityGroup: d.Get("security_group").(string),
|
||||||
}
|
}
|
||||||
|
|
||||||
server.DynamicIPRequired = Bool(d.Get("dynamic_ip_required").(bool))
|
server.DynamicIPRequired = Bool(d.Get("dynamic_ip_required").(bool))
|
||||||
|
@ -127,8 +138,9 @@ func resourceScalewayServerRead(d *schema.ResourceData, m interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Set("ipv4_address_private", server.PrivateIP)
|
d.Set("private_ip", server.PrivateIP)
|
||||||
d.Set("ipv4_address_public", server.PublicAddress.IP)
|
d.Set("public_ip", server.PublicAddress.IP)
|
||||||
|
|
||||||
d.Set("state", server.State)
|
d.Set("state", server.State)
|
||||||
d.Set("state_detail", server.StateDetail)
|
d.Set("state_detail", server.StateDetail)
|
||||||
d.Set("tags", server.Tags)
|
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") {
|
if d.HasChange("dynamic_ip_required") {
|
||||||
req.DynamicIPRequired = Bool(d.Get("dynamic_ip_required").(bool))
|
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 {
|
if err := scaleway.PatchServer(d.Id(), req); err != nil {
|
||||||
return fmt.Errorf("Failed patching scaleway server: %q", err)
|
return fmt.Errorf("Failed patching scaleway server: %q", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
func testAccCheckScalewayServerDestroy(s *terraform.State) error {
|
||||||
client := testAccProvider.Meta().(*Client).scaleway
|
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 {
|
func testAccCheckScalewayServerExists(n string) resource.TestCheckFunc {
|
||||||
return func(s *terraform.State) error {
|
return func(s *terraform.State) error {
|
||||||
rs, ok := s.RootModule().Resources[n]
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
@ -114,3 +160,43 @@ resource "scaleway_server" "base" {
|
||||||
type = "C1"
|
type = "C1"
|
||||||
tags = [ "terraform-test" ]
|
tags = [ "terraform-test" ]
|
||||||
}`, armImageIdentifier)
|
}`, 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)
|
||||||
|
|
|
@ -98,7 +98,7 @@ func (e ScalewayAPIError) Error() string {
|
||||||
"Message": e.Message,
|
"Message": e.Message,
|
||||||
"APIMessage": e.APIMessage,
|
"APIMessage": e.APIMessage,
|
||||||
} {
|
} {
|
||||||
fmt.Fprintf(&b, " %-30s %s", fmt.Sprintf("%s: ", k), v)
|
fmt.Fprintf(&b, "%s: %v ", k, v)
|
||||||
}
|
}
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
@ -420,12 +420,12 @@ type ScalewayGetSecurityGroup struct {
|
||||||
// ScalewayIPDefinition represents the IP's fields
|
// ScalewayIPDefinition represents the IP's fields
|
||||||
type ScalewayIPDefinition struct {
|
type ScalewayIPDefinition struct {
|
||||||
Organization string `json:"organization"`
|
Organization string `json:"organization"`
|
||||||
Reverse string `json:"reverse"`
|
Reverse *string `json:"reverse"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Server struct {
|
Server *struct {
|
||||||
Identifier string `json:"id,omitempty"`
|
Identifier string `json:"id,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
} `json:"server,omitempty"`
|
} `json:"server"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,11 +448,20 @@ type ScalewaySecurityGroup struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScalewayNewSecurityGroup definition POST/PUT request /security_groups
|
// ScalewayNewSecurityGroup definition POST request /security_groups
|
||||||
type ScalewayNewSecurityGroup struct {
|
type ScalewayNewSecurityGroup struct {
|
||||||
Organization string `json:"organization"`
|
Organization string `json:"organization"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
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
|
// ScalewayServer represents a Scaleway server
|
||||||
|
@ -584,6 +593,8 @@ type ScalewayServerDefinition struct {
|
||||||
PublicIP string `json:"public_ip,omitempty"`
|
PublicIP string `json:"public_ip,omitempty"`
|
||||||
|
|
||||||
EnableIPV6 bool `json:"enable_ipv6,omitempty"`
|
EnableIPV6 bool `json:"enable_ipv6,omitempty"`
|
||||||
|
|
||||||
|
SecurityGroup string `json:"security_group,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScalewayOneServer represents the response of a GET /servers/UUID API call
|
// 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
|
// NewScalewayAPI creates a ready-to-use ScalewayAPI client
|
||||||
func NewScalewayAPI(organization, token, userAgent string, options ...func(*ScalewayAPI)) (*ScalewayAPI, error) {
|
func NewScalewayAPI(organization, token, userAgent string, options ...func(*ScalewayAPI)) (*ScalewayAPI, error) {
|
||||||
cache, err := NewScalewayCache()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s := &ScalewayAPI{
|
s := &ScalewayAPI{
|
||||||
// exposed
|
// exposed
|
||||||
Organization: organization,
|
Organization: organization,
|
||||||
Token: token,
|
Token: token,
|
||||||
Cache: cache,
|
|
||||||
Logger: NewDefaultLogger(),
|
Logger: NewDefaultLogger(),
|
||||||
verbose: os.Getenv("SCW_VERBOSE_API") != "",
|
|
||||||
password: "",
|
|
||||||
userAgent: userAgent,
|
|
||||||
|
|
||||||
// internal
|
// internal
|
||||||
client: &http.Client{},
|
client: &http.Client{},
|
||||||
|
verbose: os.Getenv("SCW_VERBOSE_API") != "",
|
||||||
|
password: "",
|
||||||
|
userAgent: userAgent,
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(s)
|
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" {
|
if os.Getenv("SCW_TLSVERIFY") == "0" {
|
||||||
s.client.Transport = &http.Transport{
|
s.client.Transport = &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
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
|
// ResolveServer attempts to find a matching Identifier for the input string
|
||||||
func (s *ScalewayAPI) ResolveServer(needle string) (ScalewayResolverResults, error) {
|
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 len(servers) == 0 {
|
||||||
if _, err := s.GetServers(true, 0); err != nil {
|
if _, err = s.GetServers(true, 0); err != nil {
|
||||||
return nil, err
|
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
|
// ResolveVolume attempts to find a matching Identifier for the input string
|
||||||
func (s *ScalewayAPI) ResolveVolume(needle string) (ScalewayResolverResults, error) {
|
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 len(volumes) == 0 {
|
||||||
if _, err := s.GetVolumes(); err != nil {
|
if _, err = s.GetVolumes(); err != nil {
|
||||||
return nil, err
|
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
|
// ResolveSnapshot attempts to find a matching Identifier for the input string
|
||||||
func (s *ScalewayAPI) ResolveSnapshot(needle string) (ScalewayResolverResults, error) {
|
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 len(snapshots) == 0 {
|
||||||
if _, err := s.GetSnapshots(); err != nil {
|
if _, err = s.GetSnapshots(); err != nil {
|
||||||
return nil, err
|
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
|
// ResolveImage attempts to find a matching Identifier for the input string
|
||||||
func (s *ScalewayAPI) ResolveImage(needle string) (ScalewayResolverResults, error) {
|
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 len(images) == 0 {
|
||||||
if _, err := s.GetImages(); err != nil {
|
if _, err = s.GetImages(); err != nil {
|
||||||
return nil, err
|
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
|
// ResolveBootscript attempts to find a matching Identifier for the input string
|
||||||
func (s *ScalewayAPI) ResolveBootscript(needle string) (ScalewayResolverResults, error) {
|
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 len(bootscripts) == 0 {
|
||||||
if _, err := s.GetBootscripts(); err != nil {
|
if _, err = s.GetBootscripts(); err != nil {
|
||||||
return nil, err
|
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
|
// GetImages gets the list of images from the ScalewayAPI
|
||||||
|
@ -2154,7 +2179,7 @@ func (s *ScalewayAPI) DeleteSecurityGroup(securityGroupID string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutSecurityGroup updates a SecurityGroup
|
// 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)
|
resp, err := s.PutResponse(ComputeAPI, fmt.Sprintf("security_groups/%s", securityGroupID), group)
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
@ -2313,6 +2338,24 @@ func (s *ScalewayAPI) AttachIP(ipID, serverID string) error {
|
||||||
return err
|
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
|
// DeleteIP deletes an IP
|
||||||
func (s *ScalewayAPI) DeleteIP(ipID string) error {
|
func (s *ScalewayAPI) DeleteIP(ipID string) error {
|
||||||
resp, err := s.DeleteResponse(ComputeAPI, fmt.Sprintf("ips/%s", ipID))
|
resp, err := s.DeleteResponse(ComputeAPI, fmt.Sprintf("ips/%s", ipID))
|
||||||
|
@ -2322,12 +2365,9 @@ func (s *ScalewayAPI) DeleteIP(ipID string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, err = s.handleHTTPError([]int{204}, resp)
|
||||||
if _, err := s.handleHTTPError([]int{204}, resp); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetIP returns a ScalewayGetIP
|
// GetIP returns a ScalewayGetIP
|
||||||
func (s *ScalewayAPI) GetIP(ipID string) (*ScalewayGetIP, error) {
|
func (s *ScalewayAPI) GetIP(ipID string) (*ScalewayGetIP, error) {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -60,6 +59,8 @@ type ScalewayCache struct {
|
||||||
|
|
||||||
// Lock allows ScalewayCache to be used concurrently
|
// Lock allows ScalewayCache to be used concurrently
|
||||||
Lock sync.Mutex `json:"-"`
|
Lock sync.Mutex `json:"-"`
|
||||||
|
|
||||||
|
hookSave func()
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -92,16 +93,16 @@ type ScalewayResolverResult struct {
|
||||||
type ScalewayResolverResults []ScalewayResolverResult
|
type ScalewayResolverResults []ScalewayResolverResult
|
||||||
|
|
||||||
// NewScalewayResolverResult returns a new 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 {
|
if err := anonuuid.IsUUID(Identifier); err != nil {
|
||||||
log.Fatal(err)
|
return ScalewayResolverResult{}, err
|
||||||
}
|
}
|
||||||
return ScalewayResolverResult{
|
return ScalewayResolverResult{
|
||||||
Identifier: Identifier,
|
Identifier: Identifier,
|
||||||
Type: Type,
|
Type: Type,
|
||||||
Name: Name,
|
Name: Name,
|
||||||
Arch: Arch,
|
Arch: Arch,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ScalewayResolverResults) Len() int {
|
func (s ScalewayResolverResults) Len() int {
|
||||||
|
@ -160,7 +161,10 @@ REDO:
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScalewayCache loads a per-user cache
|
// 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
|
homeDir := os.Getenv("HOME") // *nix
|
||||||
if homeDir == "" { // Windows
|
if homeDir == "" { // Windows
|
||||||
homeDir = os.Getenv("USERPROFILE")
|
homeDir = os.Getenv("USERPROFILE")
|
||||||
|
@ -169,7 +173,6 @@ func NewScalewayCache() (*ScalewayCache, error) {
|
||||||
homeDir = "/tmp"
|
homeDir = "/tmp"
|
||||||
}
|
}
|
||||||
cachePath := filepath.Join(homeDir, ".scw-cache.db")
|
cachePath := filepath.Join(homeDir, ".scw-cache.db")
|
||||||
var cache ScalewayCache
|
|
||||||
cache.Path = cachePath
|
cache.Path = cachePath
|
||||||
_, err := os.Stat(cachePath)
|
_, err := os.Stat(cachePath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
@ -210,13 +213,13 @@ func NewScalewayCache() (*ScalewayCache, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear removes all information from the cache
|
// Clear removes all information from the cache
|
||||||
func (s *ScalewayCache) Clear() {
|
func (c *ScalewayCache) Clear() {
|
||||||
s.Images = make(map[string][CacheMaxfield]string)
|
c.Images = make(map[string][CacheMaxfield]string)
|
||||||
s.Snapshots = make(map[string][CacheMaxfield]string)
|
c.Snapshots = make(map[string][CacheMaxfield]string)
|
||||||
s.Volumes = make(map[string][CacheMaxfield]string)
|
c.Volumes = make(map[string][CacheMaxfield]string)
|
||||||
s.Bootscripts = make(map[string][CacheMaxfield]string)
|
c.Bootscripts = make(map[string][CacheMaxfield]string)
|
||||||
s.Servers = make(map[string][CacheMaxfield]string)
|
c.Servers = make(map[string][CacheMaxfield]string)
|
||||||
s.Modified = true
|
c.Modified = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush flushes the cache database
|
// Flush flushes the cache database
|
||||||
|
@ -229,8 +232,7 @@ func (c *ScalewayCache) Save() error {
|
||||||
c.Lock.Lock()
|
c.Lock.Lock()
|
||||||
defer c.Lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
log.Printf("Writing cache file to disk")
|
c.hookSave()
|
||||||
|
|
||||||
if c.Modified {
|
if c.Modified {
|
||||||
file, err := ioutil.TempFile(filepath.Dir(c.Path), filepath.Base(c.Path))
|
file, err := ioutil.TempFile(filepath.Dir(c.Path), filepath.Base(c.Path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -259,15 +261,19 @@ func (s *ScalewayResolverResult) ComputeRankMatch(needle string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookUpImages attempts to return identifiers matching a pattern
|
// 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()
|
c.Lock.Lock()
|
||||||
defer c.Lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
var res ScalewayResolverResults
|
var res ScalewayResolverResults
|
||||||
|
var exactMatches ScalewayResolverResults
|
||||||
|
|
||||||
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
||||||
if fields, ok := c.Images[needle]; ok {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
|
@ -276,41 +282,53 @@ func (c *ScalewayCache) LookUpImages(needle string, acceptUUID bool) ScalewayRes
|
||||||
needle = regexp.MustCompile(`^user/`).ReplaceAllString(needle, "")
|
needle = regexp.MustCompile(`^user/`).ReplaceAllString(needle, "")
|
||||||
// FIXME: if 'user/' is in needle, only watch for a user image
|
// FIXME: if 'user/' is in needle, only watch for a user image
|
||||||
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
||||||
var exactMatches ScalewayResolverResults
|
|
||||||
for identifier, fields := range c.Images {
|
for identifier, fields := range c.Images {
|
||||||
if fields[CacheTitle] == needle {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
exactMatches = append(exactMatches, entry)
|
exactMatches = append(exactMatches, entry)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
} else if strings.HasPrefix(fields[CacheMarketPlaceUUID], needle) || nameRegex.MatchString(fields[CacheMarketPlaceUUID]) {
|
} 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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(exactMatches) == 1 {
|
if len(exactMatches) == 1 {
|
||||||
return exactMatches
|
return exactMatches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeDuplicatesResults(res)
|
return removeDuplicatesResults(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookUpSnapshots attempts to return identifiers matching a pattern
|
// 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()
|
c.Lock.Lock()
|
||||||
defer c.Lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
var res ScalewayResolverResults
|
var res ScalewayResolverResults
|
||||||
|
var exactMatches ScalewayResolverResults
|
||||||
|
|
||||||
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
||||||
if fields, ok := c.Snapshots[needle]; ok {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
|
@ -318,136 +336,168 @@ func (c *ScalewayCache) LookUpSnapshots(needle string, acceptUUID bool) Scaleway
|
||||||
|
|
||||||
needle = regexp.MustCompile(`^user/`).ReplaceAllString(needle, "")
|
needle = regexp.MustCompile(`^user/`).ReplaceAllString(needle, "")
|
||||||
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
||||||
var exactMatches ScalewayResolverResults
|
|
||||||
for identifier, fields := range c.Snapshots {
|
for identifier, fields := range c.Snapshots {
|
||||||
if fields[CacheTitle] == needle {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
exactMatches = append(exactMatches, entry)
|
exactMatches = append(exactMatches, entry)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(exactMatches) == 1 {
|
if len(exactMatches) == 1 {
|
||||||
return exactMatches
|
return exactMatches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeDuplicatesResults(res)
|
return removeDuplicatesResults(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookUpVolumes attempts to return identifiers matching a pattern
|
// 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()
|
c.Lock.Lock()
|
||||||
defer c.Lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
var res ScalewayResolverResults
|
var res ScalewayResolverResults
|
||||||
|
var exactMatches ScalewayResolverResults
|
||||||
|
|
||||||
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
||||||
if fields, ok := c.Volumes[needle]; ok {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
||||||
var exactMatches ScalewayResolverResults
|
|
||||||
for identifier, fields := range c.Volumes {
|
for identifier, fields := range c.Volumes {
|
||||||
if fields[CacheTitle] == needle {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
exactMatches = append(exactMatches, entry)
|
exactMatches = append(exactMatches, entry)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(exactMatches) == 1 {
|
if len(exactMatches) == 1 {
|
||||||
return exactMatches
|
return exactMatches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeDuplicatesResults(res)
|
return removeDuplicatesResults(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookUpBootscripts attempts to return identifiers matching a pattern
|
// 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()
|
c.Lock.Lock()
|
||||||
defer c.Lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
var res ScalewayResolverResults
|
var res ScalewayResolverResults
|
||||||
|
var exactMatches ScalewayResolverResults
|
||||||
|
|
||||||
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
||||||
if fields, ok := c.Bootscripts[needle]; ok {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
||||||
var exactMatches ScalewayResolverResults
|
|
||||||
for identifier, fields := range c.Bootscripts {
|
for identifier, fields := range c.Bootscripts {
|
||||||
if fields[CacheTitle] == needle {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
exactMatches = append(exactMatches, entry)
|
exactMatches = append(exactMatches, entry)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(exactMatches) == 1 {
|
if len(exactMatches) == 1 {
|
||||||
return exactMatches
|
return exactMatches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeDuplicatesResults(res)
|
return removeDuplicatesResults(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookUpServers attempts to return identifiers matching a pattern
|
// 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()
|
c.Lock.Lock()
|
||||||
defer c.Lock.Unlock()
|
defer c.Lock.Unlock()
|
||||||
|
|
||||||
var res ScalewayResolverResults
|
var res ScalewayResolverResults
|
||||||
|
var exactMatches ScalewayResolverResults
|
||||||
|
|
||||||
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
if acceptUUID && anonuuid.IsUUID(needle) == nil {
|
||||||
if fields, ok := c.Servers[needle]; ok {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
|
||||||
var exactMatches ScalewayResolverResults
|
|
||||||
for identifier, fields := range c.Servers {
|
for identifier, fields := range c.Servers {
|
||||||
if fields[CacheTitle] == needle {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
exactMatches = append(exactMatches, entry)
|
exactMatches = append(exactMatches, entry)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) {
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
res = append(res, entry)
|
res = append(res, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(exactMatches) == 1 {
|
if len(exactMatches) == 1 {
|
||||||
return exactMatches
|
return exactMatches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeDuplicatesResults(res)
|
return removeDuplicatesResults(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeDuplicatesResults transforms an array into a unique array
|
// 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
|
// 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{}
|
results := ScalewayResolverResults{}
|
||||||
|
|
||||||
identifierType, needle := parseNeedle(needle)
|
identifierType, needle := parseNeedle(needle)
|
||||||
|
|
||||||
if identifierType&(IdentifierUnknown|IdentifierServer) > 0 {
|
if identifierType&(IdentifierUnknown|IdentifierServer) > 0 {
|
||||||
for _, result := range c.LookUpServers(needle, false) {
|
servers, err := c.LookUpServers(needle, false)
|
||||||
entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierServer)
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
results = append(results, entry)
|
results = append(results, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if identifierType&(IdentifierUnknown|IdentifierImage) > 0 {
|
if identifierType&(IdentifierUnknown|IdentifierImage) > 0 {
|
||||||
for _, result := range c.LookUpImages(needle, false) {
|
images, err := c.LookUpImages(needle, false)
|
||||||
entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierImage)
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
results = append(results, entry)
|
results = append(results, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if identifierType&(IdentifierUnknown|IdentifierSnapshot) > 0 {
|
if identifierType&(IdentifierUnknown|IdentifierSnapshot) > 0 {
|
||||||
for _, result := range c.LookUpSnapshots(needle, false) {
|
snapshots, err := c.LookUpSnapshots(needle, false)
|
||||||
entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierSnapshot)
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
results = append(results, entry)
|
results = append(results, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if identifierType&(IdentifierUnknown|IdentifierVolume) > 0 {
|
if identifierType&(IdentifierUnknown|IdentifierVolume) > 0 {
|
||||||
for _, result := range c.LookUpVolumes(needle, false) {
|
volumes, err := c.LookUpVolumes(needle, false)
|
||||||
entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierVolume)
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
results = append(results, entry)
|
results = append(results, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if identifierType&(IdentifierUnknown|IdentifierBootscript) > 0 {
|
if identifierType&(IdentifierUnknown|IdentifierBootscript) > 0 {
|
||||||
for _, result := range c.LookUpBootscripts(needle, false) {
|
bootscripts, err := c.LookUpBootscripts(needle, false)
|
||||||
entry := NewScalewayResolverResult(result.Identifier, result.Name, result.Arch, IdentifierBootscript)
|
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)
|
entry.ComputeRankMatch(needle)
|
||||||
results = append(results, entry)
|
results = append(results, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return results, nil
|
||||||
return results
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertServer registers a server in the cache
|
// InsertServer registers a server in the cache
|
||||||
|
|
|
@ -32,18 +32,46 @@ type defaultLogger struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *defaultLogger) LogHTTP(r *http.Request) {
|
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{}) {
|
func (l *defaultLogger) Fatalf(format string, v ...interface{}) {
|
||||||
l.Printf("[FATAL] %s\n", fmt.Sprintf(format, v))
|
l.Printf("[FATAL] %s\n", fmt.Sprintf(format, v))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *defaultLogger) Debugf(format string, v ...interface{}) {
|
func (l *defaultLogger) Debugf(format string, v ...interface{}) {
|
||||||
l.Printf("[DEBUG] %s\n", fmt.Sprintf(format, v))
|
l.Printf("[DEBUG] %s\n", fmt.Sprintf(format, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *defaultLogger) Infof(format string, v ...interface{}) {
|
func (l *defaultLogger) Infof(format string, v ...interface{}) {
|
||||||
l.Printf("[INFO ] %s\n", fmt.Sprintf(format, v))
|
l.Printf("[INFO ] %s\n", fmt.Sprintf(format, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *defaultLogger) Warnf(format string, v ...interface{}) {
|
func (l *defaultLogger) Warnf(format string, v ...interface{}) {
|
||||||
l.Printf("[WARN ] %s\n", fmt.Sprintf(format, v))
|
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{}) {
|
||||||
|
}
|
||||||
|
|
|
@ -28,11 +28,18 @@ The following arguments are supported:
|
||||||
* `name` - (Required) name of ARM server
|
* `name` - (Required) name of ARM server
|
||||||
* `image` - (Required) base image of ARM server
|
* `image` - (Required) base image of ARM server
|
||||||
* `type` - (Required) type 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
|
## Attributes Reference
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
|
||||||
* `id` - id of the new resource
|
* `id` - id of the new resource
|
||||||
|
* `private_ip` - private ip of the new resource
|
||||||
|
* `public_ip` - public ip of the new resource
|
||||||
|
|
Loading…
Reference in New Issue