From 3ecab76be8601b31bab7c27ba3608553f838e043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=AFla=20MARABESE?= Date: Mon, 26 Sep 2022 15:56:14 +0200 Subject: [PATCH] added vendor for scaleway-sdk-go/api/instance --- go.sum | 1 + pkg/apis/kops/v1alpha2/cluster.go | 6 + .../api/instance/v1/image_utils.go | 56 + .../api/instance/v1/instance_metadata_sdk.go | 281 + .../api/instance/v1/instance_sdk.go | 5059 +++++++++++++++++ .../api/instance/v1/instance_utils.go | 332 ++ .../api/instance/v1/security_group_utils.go | 218 + .../api/instance/v1/server_utils.go | 409 ++ .../api/instance/v1/snapshot_utils.go | 117 + .../api/instance/v1/volume_utils.go | 56 + .../api/marketplace/v1/marketplace_sdk.go | 304 + .../api/marketplace/v1/marketplace_utils.go | 99 + .../scaleway-sdk-go/internal/async/wait.go | 90 + .../internal/marshaler/duration.go | 160 + .../internal/parameter/query.go | 33 + .../namegenerator/name_generator.go | 863 +++ vendor/modules.txt | 6 + 17 files changed, 8090 insertions(+) create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/image_utils.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_metadata_sdk.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_sdk.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_utils.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/security_group_utils.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/server_utils.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/snapshot_utils.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/volume_utils.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_sdk.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_utils.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/internal/async/wait.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/internal/marshaler/duration.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/internal/parameter/query.go create mode 100644 vendor/github.com/scaleway/scaleway-sdk-go/namegenerator/name_generator.go diff --git a/go.sum b/go.sum index abfbfcd103..5509423168 100644 --- a/go.sum +++ b/go.sum @@ -281,6 +281,7 @@ github.com/digitalocean/godo v1.85.0/go.mod h1:jELt1jkHVifd0rKaY0pt/m1QxGzbkkvoV github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269 h1:hbCT8ZPPMqefiAWD2ZKjn7ypokIGViTvBBg/ExLSdCk= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= diff --git a/pkg/apis/kops/v1alpha2/cluster.go b/pkg/apis/kops/v1alpha2/cluster.go index 1d6ed7fbcc..de495ace50 100644 --- a/pkg/apis/kops/v1alpha2/cluster.go +++ b/pkg/apis/kops/v1alpha2/cluster.go @@ -218,6 +218,12 @@ type ClusterSpec struct { Karpenter *KarpenterConfig `json:"karpenter,omitempty"` // PodIdentityWebhook determines the EKS Pod Identity Webhook configuration. PodIdentityWebhook *PodIdentityWebhookConfig `json:"podIdentityWebhook,omitempty"` + // Scaleway configures the Scaleway cloud provider. + Scaleway *ScalewaySpec `json:"scaleway,omitempty"` +} + +// ScalewaySpec configures the Scaleway cloud provider +type ScalewaySpec struct { } // PodIdentityWebhookConfig configures an EKS Pod Identity Webhook. diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/image_utils.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/image_utils.go new file mode 100644 index 0000000000..99538fdff1 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/image_utils.go @@ -0,0 +1,56 @@ +package instance + +import ( + "time" + + "github.com/scaleway/scaleway-sdk-go/internal/async" + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +// WaitForImageRequest is used by WaitForImage method. +type WaitForImageRequest struct { + ImageID string + Zone scw.Zone + Timeout *time.Duration + RetryInterval *time.Duration +} + +// WaitForImage wait for the image to be in a "terminal state" before returning. +func (s *API) WaitForImage(req *WaitForImageRequest, opts ...scw.RequestOption) (*Image, error) { + timeout := defaultTimeout + if req.Timeout != nil { + timeout = *req.Timeout + } + retryInterval := defaultRetryInterval + if req.RetryInterval != nil { + retryInterval = *req.RetryInterval + } + + terminalStatus := map[ImageState]struct{}{ + ImageStateAvailable: {}, + ImageStateError: {}, + } + + image, err := async.WaitSync(&async.WaitSyncConfig{ + Get: func() (interface{}, bool, error) { + res, err := s.GetImage(&GetImageRequest{ + ImageID: req.ImageID, + Zone: req.Zone, + }, opts...) + + if err != nil { + return nil, false, err + } + _, isTerminal := terminalStatus[res.Image.State] + + return res.Image, isTerminal, err + }, + Timeout: timeout, + IntervalStrategy: async.LinearIntervalStrategy(retryInterval), + }) + if err != nil { + return nil, errors.Wrap(err, "waiting for image failed") + } + return image.(*Image), nil +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_metadata_sdk.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_metadata_sdk.go new file mode 100644 index 0000000000..5cba7531a5 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_metadata_sdk.go @@ -0,0 +1,281 @@ +package instance + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "math/rand" + "net" + "net/http" + "strconv" + "time" + + "github.com/scaleway/scaleway-sdk-go/internal/errors" +) + +var ( + metadataURL = "http://169.254.42.42" + metadataRetryBindPort = 200 +) + +// MetadataAPI metadata API +type MetadataAPI struct { +} + +// NewMetadataAPI returns a MetadataAPI object from a Scaleway client. +func NewMetadataAPI() *MetadataAPI { + return &MetadataAPI{} +} + +// GetMetadata returns the metadata available from the server +func (*MetadataAPI) GetMetadata() (m *Metadata, err error) { + resp, err := http.Get(metadataURL + "/conf?format=json") + if err != nil { + return nil, errors.Wrap(err, "error getting metadataURL") + } + defer resp.Body.Close() + + metadata := &Metadata{} + err = json.NewDecoder(resp.Body).Decode(metadata) + if err != nil { + return nil, errors.Wrap(err, "error decoding metadata") + } + return metadata, nil +} + +// Metadata represents the struct return by the metadata API +type Metadata struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Hostname string `json:"hostname,omitempty"` + Organization string `json:"organization,omitempty"` + Project string `json:"project,omitempty"` + CommercialType string `json:"commercial_type,omitempty"` + PublicIP struct { + Dynamic bool `json:"dynamic,omitempty"` + ID string `json:"id,omitempty"` + Address string `json:"address,omitempty"` + } `json:"public_ip,omitempty"` + PrivateIP string `json:"private_ip,omitempty"` + IPv6 struct { + Netmask string `json:"netmask,omitempty"` + Gateway string `json:"gateway,omitempty"` + Address string `json:"address,omitempty"` + } `json:"ipv6,omitempty"` + Location struct { + PlatformID string `json:"platform_id,omitempty"` + HypervisorID string `json:"hypervisor_id,omitempty"` + NodeID string `json:"node_id,omitempty"` + ClusterID string `json:"cluster_id,omitempty"` + ZoneID string `json:"zone_id,omitempty"` + } `json:"location,omitempty"` + Tags []string `json:"tags,omitempty"` + StateDetail string `json:"state_detail,omitempty"` + SSHPublicKeys []struct { + Description string `json:"description,omitempty"` + ModificationDate string `json:"modification_date,omitempty"` + IP string `json:"ip,omitempty"` + Key string `json:"key,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` + ID string `json:"id,omitempty"` + CreationDate string `json:"creation_date,omitempty"` + } `json:"ssh_public_keys,omitempty"` + Timezone string `json:"timezone,omitempty"` + Bootscript struct { + Kernel string `json:"kernel,omitempty"` + Title string `json:"title,omitempty"` + Default bool `json:"default,omitempty"` + Dtb string `json:"dtb,omitempty"` + Public bool `json:"publc,omitempty"` + Initrd string `json:"initrd,omitempty"` + Bootcmdargs string `json:"bootcmdargs,omitempty"` + Architecture string `json:"architecture,omitempty"` + Organization string `json:"organization,omitempty"` + Project string `json:"project,omitempty"` + ID string `json:"id,omitempty"` + } `json:"bootscript,omitempty"` + Volumes map[string]struct { + Name string `json:"name,omitempty"` + ModificationDate string `json:"modification_date,omitempty"` + ExportURI string `json:"export_uri,omitempty"` + VolumeType string `json:"volume_type,omitempty"` + CreationDate string `json:"creation_date,omitempty"` + State string `json:"state,omitempty"` + Organization string `json:"organization,omitempty"` + Project string `json:"project,omitempty"` + Server struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + } `json:"server,omitempty"` + ID string `json:"id,omitempty"` + Size int `json:"size,omitempty"` + } `json:"volumes,omitempty"` + PrivateNICs []struct { + ID string `json:"id,omitempty"` + PrivateNetworkID string `json:"private_network_id,omitempty"` + ServerID string `json:"server_id,omitempty"` + MacAddress string `json:"mac_address,omitempty"` + CreationDate string `json:"creation_date,omitempty"` + Zone string `json:"zone,omitempty"` + } `json:"private_nics,omitempty"` +} + +// ListUserData returns the metadata available from the server +func (*MetadataAPI) ListUserData() (res *UserData, err error) { + retries := 0 + for retries <= metadataRetryBindPort { + port := rand.Intn(1024) + localTCPAddr, err := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(port)) + if err != nil { + return nil, errors.Wrap(err, "error resolving tcp address") + } + + userdataClient := &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + LocalAddr: localTCPAddr, + DualStack: false, + FallbackDelay: time.Second * -1, + }).DialContext, + }, + } + + resp, err := userdataClient.Get(metadataURL + "/user_data?format=json") + if err != nil { + retries++ // retry with a different source port + continue + } + defer resp.Body.Close() + + userdata := &UserData{} + err = json.NewDecoder(resp.Body).Decode(userdata) + if err != nil { + return nil, errors.Wrap(err, "error decoding userdata") + } + return userdata, nil + } + return nil, errors.New("too many bind port retries for ListUserData") +} + +// GetUserData returns the value for the given metadata key +func (*MetadataAPI) GetUserData(key string) ([]byte, error) { + if key == "" { + return make([]byte, 0), errors.New("key must not be empty in GetUserData") + } + + retries := 0 + for retries <= metadataRetryBindPort { + port := rand.Intn(1024) + localTCPAddr, err := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(port)) + if err != nil { + return make([]byte, 0), errors.Wrap(err, "error resolving tcp address") + } + + userdataClient := &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + LocalAddr: localTCPAddr, + DualStack: false, + FallbackDelay: time.Second * -1, + }).DialContext, + }, + } + + resp, err := userdataClient.Get(metadataURL + "/user_data/" + key) + if err != nil { + retries++ // retry with a different source port + continue + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return make([]byte, 0), errors.Wrap(err, "error reading userdata body") + } + + return body, nil + } + return make([]byte, 0), errors.New("too may bind port retries for GetUserData") +} + +// SetUserData sets the userdata key with the given value +func (*MetadataAPI) SetUserData(key string, value []byte) error { + if key == "" { + return errors.New("key must not be empty in SetUserData") + } + + retries := 0 + for retries <= metadataRetryBindPort { + port := rand.Intn(1024) + localTCPAddr, err := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(port)) + if err != nil { + return errors.Wrap(err, "error resolving tcp address") + } + + userdataClient := &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + LocalAddr: localTCPAddr, + DualStack: false, + FallbackDelay: time.Second * -1, + }).DialContext, + }, + } + request, err := http.NewRequest("PATCH", metadataURL+"/user_data/"+key, bytes.NewBuffer(value)) + if err != nil { + return errors.Wrap(err, "error creating patch userdata request") + } + request.Header.Set("Content-Type", "text/plain") + _, err = userdataClient.Do(request) + if err != nil { + retries++ // retry with a different source port + continue + } + + return nil + } + return errors.New("too may bind port retries for SetUserData") +} + +// DeleteUserData deletes the userdata key and the associated value +func (*MetadataAPI) DeleteUserData(key string) error { + if key == "" { + return errors.New("key must not be empty in DeleteUserData") + } + + retries := 0 + for retries <= metadataRetryBindPort { + port := rand.Intn(1024) + localTCPAddr, err := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(port)) + if err != nil { + return errors.Wrap(err, "error resolving tcp address") + } + + userdataClient := &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + LocalAddr: localTCPAddr, + DualStack: false, + FallbackDelay: time.Second * -1, + }).DialContext, + }, + } + request, err := http.NewRequest("DELETE", metadataURL+"/user_data/"+key, bytes.NewBuffer([]byte(""))) + if err != nil { + return errors.Wrap(err, "error creating delete userdata request") + } + _, err = userdataClient.Do(request) + if err != nil { + retries++ // retry with a different source port + continue + } + + return nil + } + return errors.New("too may bind port retries for DeleteUserData") +} + +// UserData represents the user data +type UserData struct { + UserData []string `json:"user_data,omitempty"` +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_sdk.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_sdk.go new file mode 100644 index 0000000000..f645ed86b3 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_sdk.go @@ -0,0 +1,5059 @@ +// This file was automatically generated. DO NOT EDIT. +// If you have any remark or suggestion do not hesitate to open an issue. + +// Package instance provides methods and message types of the instance v1 API. +package instance + +import ( + "bytes" + "encoding/json" + "fmt" + "net" + "net/http" + "net/url" + "strings" + "time" + + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/internal/marshaler" + "github.com/scaleway/scaleway-sdk-go/internal/parameter" + "github.com/scaleway/scaleway-sdk-go/namegenerator" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +// always import dependencies +var ( + _ fmt.Stringer + _ json.Unmarshaler + _ url.URL + _ net.IP + _ http.Header + _ bytes.Reader + _ time.Time + _ = strings.Join + + _ scw.ScalewayRequest + _ marshaler.Duration + _ scw.File + _ = parameter.AddToQuery + _ = namegenerator.GetRandomName +) + +// API: instance API +type API struct { + client *scw.Client +} + +// NewAPI returns a API object from a Scaleway client. +func NewAPI(client *scw.Client) *API { + return &API{ + client: client, + } +} + +type Arch string + +const ( + // ArchX86_64 is [insert doc]. + ArchX86_64 = Arch("x86_64") + // ArchArm is [insert doc]. + ArchArm = Arch("arm") +) + +func (enum Arch) String() string { + if enum == "" { + // return default value if empty + return "x86_64" + } + return string(enum) +} + +func (enum Arch) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *Arch) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = Arch(Arch(tmp).String()) + return nil +} + +type BootType string + +const ( + // BootTypeLocal is [insert doc]. + BootTypeLocal = BootType("local") + // BootTypeBootscript is [insert doc]. + BootTypeBootscript = BootType("bootscript") + // BootTypeRescue is [insert doc]. + BootTypeRescue = BootType("rescue") +) + +func (enum BootType) String() string { + if enum == "" { + // return default value if empty + return "local" + } + return string(enum) +} + +func (enum BootType) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *BootType) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = BootType(BootType(tmp).String()) + return nil +} + +type ImageState string + +const ( + // ImageStateAvailable is [insert doc]. + ImageStateAvailable = ImageState("available") + // ImageStateCreating is [insert doc]. + ImageStateCreating = ImageState("creating") + // ImageStateError is [insert doc]. + ImageStateError = ImageState("error") +) + +func (enum ImageState) String() string { + if enum == "" { + // return default value if empty + return "available" + } + return string(enum) +} + +func (enum ImageState) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *ImageState) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = ImageState(ImageState(tmp).String()) + return nil +} + +type ListServersRequestOrder string + +const ( + // ListServersRequestOrderCreationDateDesc is [insert doc]. + ListServersRequestOrderCreationDateDesc = ListServersRequestOrder("creation_date_desc") + // ListServersRequestOrderCreationDateAsc is [insert doc]. + ListServersRequestOrderCreationDateAsc = ListServersRequestOrder("creation_date_asc") + // ListServersRequestOrderModificationDateDesc is [insert doc]. + ListServersRequestOrderModificationDateDesc = ListServersRequestOrder("modification_date_desc") + // ListServersRequestOrderModificationDateAsc is [insert doc]. + ListServersRequestOrderModificationDateAsc = ListServersRequestOrder("modification_date_asc") +) + +func (enum ListServersRequestOrder) String() string { + if enum == "" { + // return default value if empty + return "creation_date_desc" + } + return string(enum) +} + +func (enum ListServersRequestOrder) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *ListServersRequestOrder) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = ListServersRequestOrder(ListServersRequestOrder(tmp).String()) + return nil +} + +type PlacementGroupPolicyMode string + +const ( + // PlacementGroupPolicyModeOptional is [insert doc]. + PlacementGroupPolicyModeOptional = PlacementGroupPolicyMode("optional") + // PlacementGroupPolicyModeEnforced is [insert doc]. + PlacementGroupPolicyModeEnforced = PlacementGroupPolicyMode("enforced") +) + +func (enum PlacementGroupPolicyMode) String() string { + if enum == "" { + // return default value if empty + return "optional" + } + return string(enum) +} + +func (enum PlacementGroupPolicyMode) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *PlacementGroupPolicyMode) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = PlacementGroupPolicyMode(PlacementGroupPolicyMode(tmp).String()) + return nil +} + +type PlacementGroupPolicyType string + +const ( + // PlacementGroupPolicyTypeMaxAvailability is [insert doc]. + PlacementGroupPolicyTypeMaxAvailability = PlacementGroupPolicyType("max_availability") + // PlacementGroupPolicyTypeLowLatency is [insert doc]. + PlacementGroupPolicyTypeLowLatency = PlacementGroupPolicyType("low_latency") +) + +func (enum PlacementGroupPolicyType) String() string { + if enum == "" { + // return default value if empty + return "max_availability" + } + return string(enum) +} + +func (enum PlacementGroupPolicyType) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *PlacementGroupPolicyType) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = PlacementGroupPolicyType(PlacementGroupPolicyType(tmp).String()) + return nil +} + +type PrivateNICState string + +const ( + // PrivateNICStateAvailable is [insert doc]. + PrivateNICStateAvailable = PrivateNICState("available") + // PrivateNICStateSyncing is [insert doc]. + PrivateNICStateSyncing = PrivateNICState("syncing") + // PrivateNICStateSyncingError is [insert doc]. + PrivateNICStateSyncingError = PrivateNICState("syncing_error") +) + +func (enum PrivateNICState) String() string { + if enum == "" { + // return default value if empty + return "available" + } + return string(enum) +} + +func (enum PrivateNICState) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *PrivateNICState) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = PrivateNICState(PrivateNICState(tmp).String()) + return nil +} + +type SecurityGroupPolicy string + +const ( + // SecurityGroupPolicyAccept is [insert doc]. + SecurityGroupPolicyAccept = SecurityGroupPolicy("accept") + // SecurityGroupPolicyDrop is [insert doc]. + SecurityGroupPolicyDrop = SecurityGroupPolicy("drop") +) + +func (enum SecurityGroupPolicy) String() string { + if enum == "" { + // return default value if empty + return "accept" + } + return string(enum) +} + +func (enum SecurityGroupPolicy) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *SecurityGroupPolicy) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = SecurityGroupPolicy(SecurityGroupPolicy(tmp).String()) + return nil +} + +type SecurityGroupRuleAction string + +const ( + // SecurityGroupRuleActionAccept is [insert doc]. + SecurityGroupRuleActionAccept = SecurityGroupRuleAction("accept") + // SecurityGroupRuleActionDrop is [insert doc]. + SecurityGroupRuleActionDrop = SecurityGroupRuleAction("drop") +) + +func (enum SecurityGroupRuleAction) String() string { + if enum == "" { + // return default value if empty + return "accept" + } + return string(enum) +} + +func (enum SecurityGroupRuleAction) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *SecurityGroupRuleAction) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = SecurityGroupRuleAction(SecurityGroupRuleAction(tmp).String()) + return nil +} + +type SecurityGroupRuleDirection string + +const ( + // SecurityGroupRuleDirectionInbound is [insert doc]. + SecurityGroupRuleDirectionInbound = SecurityGroupRuleDirection("inbound") + // SecurityGroupRuleDirectionOutbound is [insert doc]. + SecurityGroupRuleDirectionOutbound = SecurityGroupRuleDirection("outbound") +) + +func (enum SecurityGroupRuleDirection) String() string { + if enum == "" { + // return default value if empty + return "inbound" + } + return string(enum) +} + +func (enum SecurityGroupRuleDirection) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *SecurityGroupRuleDirection) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = SecurityGroupRuleDirection(SecurityGroupRuleDirection(tmp).String()) + return nil +} + +type SecurityGroupRuleProtocol string + +const ( + // SecurityGroupRuleProtocolTCP is [insert doc]. + SecurityGroupRuleProtocolTCP = SecurityGroupRuleProtocol("TCP") + // SecurityGroupRuleProtocolUDP is [insert doc]. + SecurityGroupRuleProtocolUDP = SecurityGroupRuleProtocol("UDP") + // SecurityGroupRuleProtocolICMP is [insert doc]. + SecurityGroupRuleProtocolICMP = SecurityGroupRuleProtocol("ICMP") + // SecurityGroupRuleProtocolANY is [insert doc]. + SecurityGroupRuleProtocolANY = SecurityGroupRuleProtocol("ANY") +) + +func (enum SecurityGroupRuleProtocol) String() string { + if enum == "" { + // return default value if empty + return "TCP" + } + return string(enum) +} + +func (enum SecurityGroupRuleProtocol) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *SecurityGroupRuleProtocol) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = SecurityGroupRuleProtocol(SecurityGroupRuleProtocol(tmp).String()) + return nil +} + +type SecurityGroupState string + +const ( + // SecurityGroupStateAvailable is [insert doc]. + SecurityGroupStateAvailable = SecurityGroupState("available") + // SecurityGroupStateSyncing is [insert doc]. + SecurityGroupStateSyncing = SecurityGroupState("syncing") + // SecurityGroupStateSyncingError is [insert doc]. + SecurityGroupStateSyncingError = SecurityGroupState("syncing_error") +) + +func (enum SecurityGroupState) String() string { + if enum == "" { + // return default value if empty + return "available" + } + return string(enum) +} + +func (enum SecurityGroupState) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *SecurityGroupState) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = SecurityGroupState(SecurityGroupState(tmp).String()) + return nil +} + +type ServerAction string + +const ( + // ServerActionPoweron is [insert doc]. + ServerActionPoweron = ServerAction("poweron") + // ServerActionBackup is [insert doc]. + ServerActionBackup = ServerAction("backup") + // ServerActionStopInPlace is [insert doc]. + ServerActionStopInPlace = ServerAction("stop_in_place") + // ServerActionPoweroff is [insert doc]. + ServerActionPoweroff = ServerAction("poweroff") + // ServerActionTerminate is [insert doc]. + ServerActionTerminate = ServerAction("terminate") + // ServerActionReboot is [insert doc]. + ServerActionReboot = ServerAction("reboot") +) + +func (enum ServerAction) String() string { + if enum == "" { + // return default value if empty + return "poweron" + } + return string(enum) +} + +func (enum ServerAction) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *ServerAction) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = ServerAction(ServerAction(tmp).String()) + return nil +} + +type ServerState string + +const ( + // ServerStateRunning is [insert doc]. + ServerStateRunning = ServerState("running") + // ServerStateStopped is [insert doc]. + ServerStateStopped = ServerState("stopped") + // ServerStateStoppedInPlace is [insert doc]. + ServerStateStoppedInPlace = ServerState("stopped in place") + // ServerStateStarting is [insert doc]. + ServerStateStarting = ServerState("starting") + // ServerStateStopping is [insert doc]. + ServerStateStopping = ServerState("stopping") + // ServerStateLocked is [insert doc]. + ServerStateLocked = ServerState("locked") +) + +func (enum ServerState) String() string { + if enum == "" { + // return default value if empty + return "running" + } + return string(enum) +} + +func (enum ServerState) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *ServerState) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = ServerState(ServerState(tmp).String()) + return nil +} + +type ServerTypesAvailability string + +const ( + // ServerTypesAvailabilityAvailable is [insert doc]. + ServerTypesAvailabilityAvailable = ServerTypesAvailability("available") + // ServerTypesAvailabilityScarce is [insert doc]. + ServerTypesAvailabilityScarce = ServerTypesAvailability("scarce") + // ServerTypesAvailabilityShortage is [insert doc]. + ServerTypesAvailabilityShortage = ServerTypesAvailability("shortage") +) + +func (enum ServerTypesAvailability) String() string { + if enum == "" { + // return default value if empty + return "available" + } + return string(enum) +} + +func (enum ServerTypesAvailability) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *ServerTypesAvailability) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = ServerTypesAvailability(ServerTypesAvailability(tmp).String()) + return nil +} + +type SnapshotState string + +const ( + // SnapshotStateAvailable is [insert doc]. + SnapshotStateAvailable = SnapshotState("available") + // SnapshotStateSnapshotting is [insert doc]. + SnapshotStateSnapshotting = SnapshotState("snapshotting") + // SnapshotStateError is [insert doc]. + SnapshotStateError = SnapshotState("error") +) + +func (enum SnapshotState) String() string { + if enum == "" { + // return default value if empty + return "available" + } + return string(enum) +} + +func (enum SnapshotState) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *SnapshotState) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = SnapshotState(SnapshotState(tmp).String()) + return nil +} + +type TaskStatus string + +const ( + // TaskStatusPending is [insert doc]. + TaskStatusPending = TaskStatus("pending") + // TaskStatusStarted is [insert doc]. + TaskStatusStarted = TaskStatus("started") + // TaskStatusSuccess is [insert doc]. + TaskStatusSuccess = TaskStatus("success") + // TaskStatusFailure is [insert doc]. + TaskStatusFailure = TaskStatus("failure") + // TaskStatusRetry is [insert doc]. + TaskStatusRetry = TaskStatus("retry") +) + +func (enum TaskStatus) String() string { + if enum == "" { + // return default value if empty + return "pending" + } + return string(enum) +} + +func (enum TaskStatus) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *TaskStatus) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = TaskStatus(TaskStatus(tmp).String()) + return nil +} + +type VolumeServerState string + +const ( + // VolumeServerStateAvailable is [insert doc]. + VolumeServerStateAvailable = VolumeServerState("available") + // VolumeServerStateSnapshotting is [insert doc]. + VolumeServerStateSnapshotting = VolumeServerState("snapshotting") + // VolumeServerStateError is [insert doc]. + VolumeServerStateError = VolumeServerState("error") + // VolumeServerStateFetching is [insert doc]. + VolumeServerStateFetching = VolumeServerState("fetching") + // VolumeServerStateResizing is [insert doc]. + VolumeServerStateResizing = VolumeServerState("resizing") + // VolumeServerStateSaving is [insert doc]. + VolumeServerStateSaving = VolumeServerState("saving") + // VolumeServerStateHotsyncing is [insert doc]. + VolumeServerStateHotsyncing = VolumeServerState("hotsyncing") +) + +func (enum VolumeServerState) String() string { + if enum == "" { + // return default value if empty + return "available" + } + return string(enum) +} + +func (enum VolumeServerState) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *VolumeServerState) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = VolumeServerState(VolumeServerState(tmp).String()) + return nil +} + +type VolumeServerVolumeType string + +const ( + // VolumeServerVolumeTypeLSSD is [insert doc]. + VolumeServerVolumeTypeLSSD = VolumeServerVolumeType("l_ssd") + // VolumeServerVolumeTypeBSSD is [insert doc]. + VolumeServerVolumeTypeBSSD = VolumeServerVolumeType("b_ssd") +) + +func (enum VolumeServerVolumeType) String() string { + if enum == "" { + // return default value if empty + return "l_ssd" + } + return string(enum) +} + +func (enum VolumeServerVolumeType) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *VolumeServerVolumeType) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = VolumeServerVolumeType(VolumeServerVolumeType(tmp).String()) + return nil +} + +type VolumeState string + +const ( + // VolumeStateAvailable is [insert doc]. + VolumeStateAvailable = VolumeState("available") + // VolumeStateSnapshotting is [insert doc]. + VolumeStateSnapshotting = VolumeState("snapshotting") + // VolumeStateError is [insert doc]. + VolumeStateError = VolumeState("error") + // VolumeStateFetching is [insert doc]. + VolumeStateFetching = VolumeState("fetching") + // VolumeStateResizing is [insert doc]. + VolumeStateResizing = VolumeState("resizing") + // VolumeStateSaving is [insert doc]. + VolumeStateSaving = VolumeState("saving") + // VolumeStateHotsyncing is [insert doc]. + VolumeStateHotsyncing = VolumeState("hotsyncing") +) + +func (enum VolumeState) String() string { + if enum == "" { + // return default value if empty + return "available" + } + return string(enum) +} + +func (enum VolumeState) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *VolumeState) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = VolumeState(VolumeState(tmp).String()) + return nil +} + +type VolumeVolumeType string + +const ( + // VolumeVolumeTypeLSSD is [insert doc]. + VolumeVolumeTypeLSSD = VolumeVolumeType("l_ssd") + // VolumeVolumeTypeBSSD is [insert doc]. + VolumeVolumeTypeBSSD = VolumeVolumeType("b_ssd") +) + +func (enum VolumeVolumeType) String() string { + if enum == "" { + // return default value if empty + return "l_ssd" + } + return string(enum) +} + +func (enum VolumeVolumeType) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, enum)), nil +} + +func (enum *VolumeVolumeType) UnmarshalJSON(data []byte) error { + tmp := "" + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + *enum = VolumeVolumeType(VolumeVolumeType(tmp).String()) + return nil +} + +// Bootscript: bootscript +type Bootscript struct { + // Bootcmdargs: the bootscript arguments + Bootcmdargs string `json:"bootcmdargs"` + // Default: dispmay if the bootscript is the default bootscript if no other boot option is configured + Default bool `json:"default"` + // Dtb: provide information regarding a Device Tree Binary (dtb) for use with C1 servers + Dtb string `json:"dtb"` + // ID: the bootscript ID + ID string `json:"id"` + // Initrd: the initrd (initial ramdisk) configuration + Initrd string `json:"initrd"` + // Kernel: the server kernel version + Kernel string `json:"kernel"` + // Organization: the bootscript organization ID + Organization string `json:"organization"` + // Project: the bootscript project ID + Project string `json:"project"` + // Public: provide information if the bootscript is public + Public bool `json:"public"` + // Title: the bootscript title + Title string `json:"title"` + // Arch: the bootscript arch + // + // Default value: x86_64 + Arch Arch `json:"arch"` + // Zone: the zone in which is the bootscript + Zone scw.Zone `json:"zone"` +} + +type CreateIPResponse struct { + IP *IP `json:"ip"` + + Location string `json:"Location"` +} + +type CreateImageResponse struct { + Image *Image `json:"image"` + + Location string `json:"Location"` +} + +type CreatePlacementGroupResponse struct { + PlacementGroup *PlacementGroup `json:"placement_group"` +} + +type CreatePrivateNICResponse struct { + PrivateNic *PrivateNIC `json:"private_nic"` +} + +type CreateSecurityGroupResponse struct { + SecurityGroup *SecurityGroup `json:"security_group"` +} + +type CreateSecurityGroupRuleResponse struct { + Rule *SecurityGroupRule `json:"rule"` +} + +type CreateServerResponse struct { + Server *Server `json:"server"` +} + +type CreateSnapshotResponse struct { + Snapshot *Snapshot `json:"snapshot"` +} + +type CreateVolumeResponse struct { + Volume *Volume `json:"volume"` + + Location string `json:"Location"` +} + +type Dashboard struct { + VolumesCount uint32 `json:"volumes_count"` + + RunningServersCount uint32 `json:"running_servers_count"` + + ServersByTypes map[string]uint32 `json:"servers_by_types"` + + ImagesCount uint32 `json:"images_count"` + + SnapshotsCount uint32 `json:"snapshots_count"` + + ServersCount uint32 `json:"servers_count"` + + IPsCount uint32 `json:"ips_count"` + + SecurityGroupsCount uint32 `json:"security_groups_count"` + + IPsUnused uint32 `json:"ips_unused"` +} + +type GetBootscriptResponse struct { + Bootscript *Bootscript `json:"bootscript"` +} + +type GetDashboardResponse struct { + Dashboard *Dashboard `json:"dashboard"` +} + +type GetIPResponse struct { + IP *IP `json:"ip"` +} + +type GetImageResponse struct { + Image *Image `json:"image"` +} + +type GetPlacementGroupResponse struct { + PlacementGroup *PlacementGroup `json:"placement_group"` +} + +type GetPlacementGroupServersResponse struct { + Servers []*PlacementGroupServer `json:"servers"` +} + +type GetPrivateNICResponse struct { + PrivateNic *PrivateNIC `json:"private_nic"` +} + +type GetSecurityGroupResponse struct { + SecurityGroup *SecurityGroup `json:"security_group"` +} + +type GetSecurityGroupRuleResponse struct { + Rule *SecurityGroupRule `json:"rule"` +} + +type GetServerResponse struct { + Server *Server `json:"server"` +} + +type GetServerTypesAvailabilityResponse struct { + Servers map[string]*GetServerTypesAvailabilityResponseAvailability `json:"servers"` +} + +type GetServerTypesAvailabilityResponseAvailability struct { + // Availability: + // + // Default value: available + Availability ServerTypesAvailability `json:"availability"` +} + +type GetSnapshotResponse struct { + Snapshot *Snapshot `json:"snapshot"` +} + +type GetVolumeResponse struct { + Volume *Volume `json:"volume"` +} + +type IP struct { + ID string `json:"id"` + + Address net.IP `json:"address"` + + Reverse *string `json:"reverse"` + + Server *ServerSummary `json:"server"` + + Organization string `json:"organization"` + + Tags []string `json:"tags"` + + Project string `json:"project"` + + Zone scw.Zone `json:"zone"` +} + +type Image struct { + ID string `json:"id"` + + Name string `json:"name"` + // Arch: + // + // Default value: x86_64 + Arch Arch `json:"arch"` + + CreationDate *time.Time `json:"creation_date"` + + ModificationDate *time.Time `json:"modification_date"` + + DefaultBootscript *Bootscript `json:"default_bootscript"` + + ExtraVolumes map[string]*Volume `json:"extra_volumes"` + + FromServer string `json:"from_server"` + + Organization string `json:"organization"` + + Public bool `json:"public"` + + RootVolume *VolumeSummary `json:"root_volume"` + // State: + // + // Default value: available + State ImageState `json:"state"` + + Project string `json:"project"` + + Tags []string `json:"tags"` + + Zone scw.Zone `json:"zone"` +} + +// ListBootscriptsResponse: list bootscripts response +type ListBootscriptsResponse struct { + // TotalCount: total number of bootscripts + TotalCount uint32 `json:"total_count"` + // Bootscripts: list of bootscripts + Bootscripts []*Bootscript `json:"bootscripts"` +} + +// ListIPsResponse: list ips response +type ListIPsResponse struct { + // TotalCount: total number of ips + TotalCount uint32 `json:"total_count"` + // IPs: list of ips + IPs []*IP `json:"ips"` +} + +// ListImagesResponse: list images response +type ListImagesResponse struct { + // TotalCount: total number of images + TotalCount uint32 `json:"total_count"` + // Images: list of images + Images []*Image `json:"images"` +} + +// ListPlacementGroupsResponse: list placement groups response +type ListPlacementGroupsResponse struct { + // TotalCount: total number of placement groups + TotalCount uint32 `json:"total_count"` + // PlacementGroups: list of placement groups + PlacementGroups []*PlacementGroup `json:"placement_groups"` +} + +type ListPrivateNICsResponse struct { + PrivateNics []*PrivateNIC `json:"private_nics"` +} + +// ListSecurityGroupRulesResponse: list security group rules response +type ListSecurityGroupRulesResponse struct { + // TotalCount: total number of security groups + TotalCount uint32 `json:"total_count"` + // Rules: list of security groups + Rules []*SecurityGroupRule `json:"rules"` +} + +type ListSecurityGroupsResponse struct { + SecurityGroups []*SecurityGroup `json:"security_groups"` + + TotalCount uint32 `json:"total_count"` +} + +type ListServerActionsResponse struct { + Actions []ServerAction `json:"actions"` +} + +type ListServerUserDataResponse struct { + UserData []string `json:"user_data"` +} + +// ListServersResponse: list servers response +type ListServersResponse struct { + // TotalCount: total number of servers + TotalCount uint32 `json:"total_count"` + // Servers: list of servers + Servers []*Server `json:"servers"` +} + +// ListServersTypesResponse: list servers types response +type ListServersTypesResponse struct { + // TotalCount: total number of server types + TotalCount uint32 `json:"total_count"` + // Servers: list of server types + Servers map[string]*ServerType `json:"servers"` +} + +// ListSnapshotsResponse: list snapshots response +type ListSnapshotsResponse struct { + // TotalCount: total number of snapshots + TotalCount uint32 `json:"total_count"` + // Snapshots: list of snapshots + Snapshots []*Snapshot `json:"snapshots"` +} + +// ListVolumesResponse: list volumes response +type ListVolumesResponse struct { + // TotalCount: total number of volumes + TotalCount uint32 `json:"total_count"` + // Volumes: list of volumes + Volumes []*Volume `json:"volumes"` +} + +// ListVolumesTypesResponse: list volumes types response +type ListVolumesTypesResponse struct { + // TotalCount: total number of volume types + TotalCount uint32 `json:"total_count"` + // Volumes: map of volume types + Volumes map[string]*VolumeType `json:"volumes"` +} + +type NullableStringValue struct { + Null bool `json:"null,omitempty"` + + Value string `json:"value,omitempty"` +} + +// PlacementGroup: placement group +type PlacementGroup struct { + // ID: the placement group unique ID + ID string `json:"id"` + // Name: the placement group name + Name string `json:"name"` + // Organization: the placement group organization ID + Organization string `json:"organization"` + // Project: the placement group project ID + Project string `json:"project"` + // Tags: the placement group tags + Tags []string `json:"tags"` + // PolicyMode: select the failling mode when the placement cannot be respected, either optional or enforced + // + // Default value: optional + PolicyMode PlacementGroupPolicyMode `json:"policy_mode"` + // PolicyType: select the behavior of the placement group, either low_latency (group) or max_availability (spread) + // + // Default value: max_availability + PolicyType PlacementGroupPolicyType `json:"policy_type"` + // PolicyRespected: returns true if the policy is respected, false otherwise + PolicyRespected bool `json:"policy_respected"` + // Zone: the zone in which is the placement group + Zone scw.Zone `json:"zone"` +} + +type PlacementGroupServer struct { + ID string `json:"id"` + + Name string `json:"name"` + + PolicyRespected bool `json:"policy_respected"` +} + +// PrivateNIC: private nic +type PrivateNIC struct { + // ID: the private NIC unique ID + ID string `json:"id,omitempty"` + // ServerID: the server the private NIC is attached to + ServerID string `json:"server_id,omitempty"` + // PrivateNetworkID: the private network where the private NIC is attached + PrivateNetworkID string `json:"private_network_id,omitempty"` + // MacAddress: the private NIC MAC address + MacAddress string `json:"mac_address,omitempty"` + // State: the private NIC state + // + // Default value: available + State PrivateNICState `json:"state,omitempty"` +} + +// SecurityGroup: security group +type SecurityGroup struct { + // ID: the security groups' unique ID + ID string `json:"id"` + // Name: the security groups name + Name string `json:"name"` + // Description: the security groups description + Description string `json:"description"` + // EnableDefaultSecurity: true if SMTP is blocked on IPv4 and IPv6 + EnableDefaultSecurity bool `json:"enable_default_security"` + // InboundDefaultPolicy: the default inbound policy + // + // Default value: accept + InboundDefaultPolicy SecurityGroupPolicy `json:"inbound_default_policy"` + // OutboundDefaultPolicy: the default outbound policy + // + // Default value: accept + OutboundDefaultPolicy SecurityGroupPolicy `json:"outbound_default_policy"` + // Organization: the security groups organization ID + Organization string `json:"organization"` + // Project: the security group project ID + Project string `json:"project"` + // Tags: the security group tags + Tags []string `json:"tags"` + // Deprecated: OrganizationDefault: true if it is your default security group for this organization ID + OrganizationDefault bool `json:"organization_default"` + // ProjectDefault: true if it is your default security group for this project ID + ProjectDefault bool `json:"project_default"` + // CreationDate: the security group creation date + CreationDate *time.Time `json:"creation_date"` + // ModificationDate: the security group modification date + ModificationDate *time.Time `json:"modification_date"` + // Servers: list of servers attached to this security group + Servers []*ServerSummary `json:"servers"` + // Stateful: true if the security group is stateful + Stateful bool `json:"stateful"` + // State: security group state + // + // Default value: available + State SecurityGroupState `json:"state"` + // Zone: the zone in which is the security group + Zone scw.Zone `json:"zone"` +} + +type SecurityGroupRule struct { + ID string `json:"id"` + // Protocol: + // + // Default value: TCP + Protocol SecurityGroupRuleProtocol `json:"protocol"` + // Direction: + // + // Default value: inbound + Direction SecurityGroupRuleDirection `json:"direction"` + // Action: + // + // Default value: accept + Action SecurityGroupRuleAction `json:"action"` + + IPRange scw.IPNet `json:"ip_range"` + + DestPortFrom *uint32 `json:"dest_port_from"` + + DestPortTo *uint32 `json:"dest_port_to"` + + Position uint32 `json:"position"` + + Editable bool `json:"editable"` + + Zone scw.Zone `json:"zone"` +} + +type SecurityGroupSummary struct { + ID string `json:"id"` + + Name string `json:"name"` +} + +type SecurityGroupTemplate struct { + ID string `json:"id,omitempty"` + + Name string `json:"name,omitempty"` +} + +// Server: server +type Server struct { + // ID: the server unique ID + ID string `json:"id"` + // Name: the server name + Name string `json:"name"` + // Organization: the server organization ID + Organization string `json:"organization"` + // Project: the server project ID + Project string `json:"project"` + // AllowedActions: provide as list of allowed actions on the server + AllowedActions []ServerAction `json:"allowed_actions"` + // Tags: the server associated tags + Tags []string `json:"tags"` + // CommercialType: the server commercial type (eg. GP1-M) + CommercialType string `json:"commercial_type"` + // CreationDate: the server creation date + CreationDate *time.Time `json:"creation_date"` + // DynamicIPRequired: true if a dynamic IP is required + DynamicIPRequired bool `json:"dynamic_ip_required"` + // EnableIPv6: true if IPv6 is enabled + EnableIPv6 bool `json:"enable_ipv6"` + // Hostname: the server host name + Hostname string `json:"hostname"` + // Image: provide information on the server image + Image *Image `json:"image"` + // Protected: the server protection option is activated + Protected bool `json:"protected"` + // PrivateIP: the server private IP address + PrivateIP *string `json:"private_ip"` + // PublicIP: information about the public IP + PublicIP *ServerIP `json:"public_ip"` + // ModificationDate: the server modification date + ModificationDate *time.Time `json:"modification_date"` + // State: the server state + // + // Default value: running + State ServerState `json:"state"` + // Location: the server location + Location *ServerLocation `json:"location"` + // IPv6: the server IPv6 address + IPv6 *ServerIPv6 `json:"ipv6"` + // Bootscript: the server bootscript + Bootscript *Bootscript `json:"bootscript"` + // BootType: the server boot type + // + // Default value: local + BootType BootType `json:"boot_type"` + // Volumes: the server volumes + Volumes map[string]*VolumeServer `json:"volumes"` + // SecurityGroup: the server security group + SecurityGroup *SecurityGroupSummary `json:"security_group"` + // Maintenances: the server planned maintenances + Maintenances []*ServerMaintenance `json:"maintenances"` + // StateDetail: the server state_detail + StateDetail string `json:"state_detail"` + // Arch: the server arch + // + // Default value: x86_64 + Arch Arch `json:"arch"` + // PlacementGroup: the server placement group + PlacementGroup *PlacementGroup `json:"placement_group"` + // PrivateNics: the server private NICs + PrivateNics []*PrivateNIC `json:"private_nics"` + // Zone: the zone in which is the server + Zone scw.Zone `json:"zone"` +} + +type ServerActionResponse struct { + Task *Task `json:"task"` +} + +// ServerIP: server. ip +type ServerIP struct { + // ID: the unique ID of the IP address + ID string `json:"id"` + // Address: the server public IPv4 IP-Address + Address net.IP `json:"address"` + // Dynamic: true if the IP address is dynamic + Dynamic bool `json:"dynamic"` +} + +// ServerIPv6: server. ipv6 +type ServerIPv6 struct { + // Address: the server IPv6 IP-Address + Address net.IP `json:"address"` + // Gateway: the IPv6 IP-addresses gateway + Gateway net.IP `json:"gateway"` + // Netmask: the IPv6 IP-addresses CIDR netmask + Netmask string `json:"netmask"` +} + +type ServerLocation struct { + ClusterID string `json:"cluster_id"` + + HypervisorID string `json:"hypervisor_id"` + + NodeID string `json:"node_id"` + + PlatformID string `json:"platform_id"` + + ZoneID string `json:"zone_id"` +} + +type ServerMaintenance struct { +} + +type ServerSummary struct { + ID string `json:"id"` + + Name string `json:"name"` +} + +// ServerType: server type +type ServerType struct { + // Deprecated: MonthlyPrice: estimated monthly price, for a 30 days month, in Euro + MonthlyPrice float32 `json:"monthly_price"` + // HourlyPrice: hourly price in Euro + HourlyPrice float32 `json:"hourly_price"` + // AltNames: alternative instance name if any + AltNames []string `json:"alt_names"` + // PerVolumeConstraint: additional volume constraints + PerVolumeConstraint *ServerTypeVolumeConstraintsByType `json:"per_volume_constraint"` + // VolumesConstraint: initial volume constraints + VolumesConstraint *ServerTypeVolumeConstraintSizes `json:"volumes_constraint"` + // Ncpus: number of CPU + Ncpus uint32 `json:"ncpus"` + // Gpu: number of GPU + Gpu *uint64 `json:"gpu"` + // RAM: available RAM in bytes + RAM uint64 `json:"ram"` + // Arch: CPU architecture + // + // Default value: x86_64 + Arch Arch `json:"arch"` + // Baremetal: true if it is a baremetal instance + Baremetal bool `json:"baremetal"` + // Network: network available for the instance + Network *ServerTypeNetwork `json:"network"` +} + +// ServerTypeNetwork: server type. network +type ServerTypeNetwork struct { + // Interfaces: list of available network interfaces + Interfaces []*ServerTypeNetworkInterface `json:"interfaces"` + // SumInternalBandwidth: total maximum internal bandwidth in bits per seconds + SumInternalBandwidth *uint64 `json:"sum_internal_bandwidth"` + // SumInternetBandwidth: total maximum internet bandwidth in bits per seconds + SumInternetBandwidth *uint64 `json:"sum_internet_bandwidth"` + // IPv6Support: true if IPv6 is enabled + IPv6Support bool `json:"ipv6_support"` +} + +// ServerTypeNetworkInterface: server type. network. interface +type ServerTypeNetworkInterface struct { + // InternalBandwidth: maximum internal bandwidth in bits per seconds + InternalBandwidth *uint64 `json:"internal_bandwidth"` + // InternetBandwidth: maximum internet bandwidth in bits per seconds + InternetBandwidth *uint64 `json:"internet_bandwidth"` +} + +// ServerTypeVolumeConstraintSizes: server type. volume constraint sizes +type ServerTypeVolumeConstraintSizes struct { + // MinSize: minimum volume size in bytes + MinSize scw.Size `json:"min_size"` + // MaxSize: maximum volume size in bytes + MaxSize scw.Size `json:"max_size"` +} + +// ServerTypeVolumeConstraintsByType: server type. volume constraints by type +type ServerTypeVolumeConstraintsByType struct { + // LSSD: local SSD volumes + LSSD *ServerTypeVolumeConstraintSizes `json:"l_ssd"` +} + +type SetPlacementGroupResponse struct { + PlacementGroup *PlacementGroup `json:"placement_group"` +} + +type SetPlacementGroupServersResponse struct { + Servers []*PlacementGroupServer `json:"servers"` +} + +// Snapshot: snapshot +type Snapshot struct { + // ID: the snapshot ID + ID string `json:"id"` + // Name: the snapshot name + Name string `json:"name"` + // Organization: the snapshot organization ID + Organization string `json:"organization"` + // Project: the snapshot project ID + Project string `json:"project"` + // Tags: the snapshot tags + Tags []string `json:"tags"` + // VolumeType: the snapshot volume type + // + // Default value: l_ssd + VolumeType VolumeVolumeType `json:"volume_type"` + // Size: the snapshot size + Size scw.Size `json:"size"` + // State: the snapshot state + // + // Default value: available + State SnapshotState `json:"state"` + // BaseVolume: the volume on which the snapshot is based on + BaseVolume *SnapshotBaseVolume `json:"base_volume"` + // CreationDate: the snapshot creation date + CreationDate *time.Time `json:"creation_date"` + // ModificationDate: the snapshot modification date + ModificationDate *time.Time `json:"modification_date"` + // Zone: the snapshot zone + Zone scw.Zone `json:"zone"` +} + +// SnapshotBaseVolume: snapshot. base volume +type SnapshotBaseVolume struct { + // ID: the volume ID on which the snapshot is based on + ID string `json:"id"` + // Name: the volume name on which the snapshot is based on + Name string `json:"name"` +} + +// Task: task +type Task struct { + // ID: the unique ID of the task + ID string `json:"id"` + // Description: the description of the task + Description string `json:"description"` + // Progress: the progress of the task in percent + Progress int32 `json:"progress"` + // StartedAt: the task start date + StartedAt *time.Time `json:"started_at"` + // TerminatedAt: the task end date + TerminatedAt *time.Time `json:"terminated_at"` + // Status: the task status + // + // Default value: pending + Status TaskStatus `json:"status"` + + HrefFrom string `json:"href_from"` + + HrefResult string `json:"href_result"` + // Zone: the zone in which is the task + Zone scw.Zone `json:"zone"` +} + +type UpdateIPResponse struct { + IP *IP `json:"ip"` +} + +type UpdatePlacementGroupResponse struct { + PlacementGroup *PlacementGroup `json:"placement_group"` +} + +type UpdatePlacementGroupServersResponse struct { + Servers []*PlacementGroupServer `json:"servers"` +} + +type UpdateServerResponse struct { + Server *Server `json:"server"` +} + +type UpdateVolumeResponse struct { + Volume *Volume `json:"volume"` +} + +// Volume: volume +type Volume struct { + // ID: the volume unique ID + ID string `json:"id"` + // Name: the volume name + Name string `json:"name"` + // ExportURI: show the volume NBD export URI + ExportURI string `json:"export_uri"` + // Size: the volume disk size + Size scw.Size `json:"size"` + // VolumeType: the volume type + // + // Default value: l_ssd + VolumeType VolumeVolumeType `json:"volume_type"` + // CreationDate: the volume creation date + CreationDate *time.Time `json:"creation_date"` + // ModificationDate: the volume modification date + ModificationDate *time.Time `json:"modification_date"` + // Organization: the volume organization ID + Organization string `json:"organization"` + // Project: the volume project ID + Project string `json:"project"` + // Tags: the volume tags + Tags []string `json:"tags"` + // Server: the server attached to the volume + Server *ServerSummary `json:"server"` + // State: the volume state + // + // Default value: available + State VolumeState `json:"state"` + // Zone: the zone in which is the volume + Zone scw.Zone `json:"zone"` +} + +type VolumeServer struct { + ID string `json:"id"` + + Name string `json:"name"` + + ExportURI string `json:"export_uri"` + + Organization string `json:"organization"` + + Server *ServerSummary `json:"server"` + + Size scw.Size `json:"size"` + // VolumeType: + // + // Default value: l_ssd + VolumeType VolumeServerVolumeType `json:"volume_type"` + + CreationDate *time.Time `json:"creation_date"` + + ModificationDate *time.Time `json:"modification_date"` + // State: + // + // Default value: available + State VolumeServerState `json:"state"` + + Project string `json:"project"` + + Boot bool `json:"boot"` + + Zone scw.Zone `json:"zone"` +} + +// VolumeServerTemplate: volume server template +type VolumeServerTemplate struct { + // ID: UUID of the volume + ID string `json:"id,omitempty"` + // Boot: force the server to boot on this volume + // + // Default value: false + Boot bool `json:"boot,omitempty"` + // Name: name of the volume + Name string `json:"name,omitempty"` + // Size: disk size of the volume + Size scw.Size `json:"size,omitempty"` + // VolumeType: type of the volume + // + // Default value: l_ssd + VolumeType VolumeVolumeType `json:"volume_type,omitempty"` +} + +type VolumeSummary struct { + ID string `json:"id"` + + Name string `json:"name"` + + Size scw.Size `json:"size"` + // VolumeType: + // + // Default value: l_ssd + VolumeType VolumeVolumeType `json:"volume_type"` +} + +// VolumeTemplate: volume template +type VolumeTemplate struct { + // ID: UUID of the volume + ID string `json:"id,omitempty"` + // Name: name of the volume + Name string `json:"name,omitempty"` + // Size: disk size of the volume + Size scw.Size `json:"size,omitempty"` + // VolumeType: type of the volume + // + // Default value: l_ssd + VolumeType VolumeVolumeType `json:"volume_type,omitempty"` + // Deprecated: Organization: organization ID of the volume + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: project ID of the volume + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` +} + +type VolumeType struct { + DisplayName string `json:"display_name"` + + Capabilities *VolumeTypeCapabilities `json:"capabilities"` + + Constraints *VolumeTypeConstraints `json:"constraints"` +} + +type VolumeTypeCapabilities struct { + Snapshot bool `json:"snapshot"` +} + +type VolumeTypeConstraints struct { + Min scw.Size `json:"min"` + + Max scw.Size `json:"max"` +} + +// setImageResponse: set image response +type setImageResponse struct { + Image *Image `json:"image"` +} + +// setSecurityGroupResponse: set security group response +type setSecurityGroupResponse struct { + SecurityGroup *SecurityGroup `json:"security_group"` +} + +// setSecurityGroupRuleResponse: set security group rule response +type setSecurityGroupRuleResponse struct { + Rule *SecurityGroupRule `json:"rule"` +} + +// setServerResponse: set server response +type setServerResponse struct { + Server *Server `json:"server"` +} + +// setSnapshotResponse: set snapshot response +type setSnapshotResponse struct { + Snapshot *Snapshot `json:"snapshot"` +} + +// Service API + +type GetServerTypesAvailabilityRequest struct { + Zone scw.Zone `json:"-"` + + PerPage *uint32 `json:"-"` + + Page *int32 `json:"-"` +} + +// GetServerTypesAvailability: get availability +// +// Get availibility for all server types. +func (s *API) GetServerTypesAvailability(req *GetServerTypesAvailabilityRequest, opts ...scw.RequestOption) (*GetServerTypesAvailabilityResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/products/servers/availability", + Query: query, + Headers: http.Header{}, + } + + var resp GetServerTypesAvailabilityResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListServersTypesRequest struct { + Zone scw.Zone `json:"-"` + + PerPage *uint32 `json:"-"` + + Page *int32 `json:"-"` +} + +// ListServersTypes: list server types +// +// Get server types technical details. +func (s *API) ListServersTypes(req *ListServersTypesRequest, opts ...scw.RequestOption) (*ListServersTypesResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/products/servers", + Query: query, + Headers: http.Header{}, + } + + var resp ListServersTypesResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListVolumesTypesRequest struct { + Zone scw.Zone `json:"-"` + + PerPage *uint32 `json:"-"` + + Page *int32 `json:"-"` +} + +// ListVolumesTypes: list volumes types +// +// Get volumes technical details. +func (s *API) ListVolumesTypes(req *ListVolumesTypesRequest, opts ...scw.RequestOption) (*ListVolumesTypesResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/products/volumes", + Query: query, + Headers: http.Header{}, + } + + var resp ListVolumesTypesResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListServersRequest struct { + Zone scw.Zone `json:"-"` + // PerPage: a positive integer lower or equal to 100 to select the number of items to return + // + // Default value: 50 + PerPage *uint32 `json:"-"` + // Page: a positive integer to choose the page to return + Page *int32 `json:"-"` + // Organization: list only servers of this organization ID + Organization *string `json:"-"` + // Project: list only servers of this project ID + Project *string `json:"-"` + // Name: filter servers by name (for eg. "server1" will return "server100" and "server1" but not "foo") + Name *string `json:"-"` + // PrivateIP: list servers by private_ip + PrivateIP *net.IP `json:"-"` + // WithoutIP: list servers that are not attached to a public IP + WithoutIP *bool `json:"-"` + // CommercialType: list servers of this commercial type + CommercialType *string `json:"-"` + // State: list servers in this state + // + // Default value: running + State *ServerState `json:"-"` + // Tags: list servers with these exact tags (to filter with several tags, use commas to separate them) + Tags []string `json:"-"` + // PrivateNetwork: list servers in this Private Network + PrivateNetwork *string `json:"-"` + // Order: define the order of the returned servers + // + // Default value: creation_date_desc + Order ListServersRequestOrder `json:"-"` +} + +// ListServers: list all servers +func (s *API) ListServers(req *ListServersRequest, opts ...scw.RequestOption) (*ListServersResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "project", req.Project) + parameter.AddToQuery(query, "name", req.Name) + parameter.AddToQuery(query, "private_ip", req.PrivateIP) + parameter.AddToQuery(query, "without_ip", req.WithoutIP) + parameter.AddToQuery(query, "commercial_type", req.CommercialType) + parameter.AddToQuery(query, "state", req.State) + if len(req.Tags) != 0 { + parameter.AddToQuery(query, "tags", strings.Join(req.Tags, ",")) + } + parameter.AddToQuery(query, "private_network", req.PrivateNetwork) + parameter.AddToQuery(query, "order", req.Order) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers", + Query: query, + Headers: http.Header{}, + } + + var resp ListServersResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreateServerRequest struct { + Zone scw.Zone `json:"-"` + // Name: the server name + Name string `json:"name,omitempty"` + // DynamicIPRequired: define if a dynamic IP is required for the instance + DynamicIPRequired *bool `json:"dynamic_ip_required,omitempty"` + // CommercialType: define the server commercial type (i.e. GP1-S) + CommercialType string `json:"commercial_type,omitempty"` + // Image: the server image ID or label + Image string `json:"image,omitempty"` + // Volumes: the volumes attached to the server + Volumes map[string]*VolumeServerTemplate `json:"volumes,omitempty"` + // EnableIPv6: true if IPv6 is enabled on the server + EnableIPv6 bool `json:"enable_ipv6,omitempty"` + // PublicIP: the ID of the reserved IP to attach to the server + PublicIP *string `json:"public_ip,omitempty"` + // BootType: the boot type to use + // + // Default value: local + BootType *BootType `json:"boot_type,omitempty"` + // Bootscript: the bootscript ID to use when `boot_type` is set to `bootscript` + Bootscript *string `json:"bootscript,omitempty"` + // Deprecated: Organization: the server organization ID + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: the server project ID + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` + // Tags: the server tags + Tags []string `json:"tags,omitempty"` + // SecurityGroup: the security group ID + SecurityGroup *string `json:"security_group,omitempty"` + // PlacementGroup: placement group ID if server must be part of a placement group + PlacementGroup *string `json:"placement_group,omitempty"` +} + +// createServer: create a server +func (s *API) createServer(req *CreateServerRequest, opts ...scw.RequestOption) (*CreateServerResponse, error) { + var err error + + defaultProject, exist := s.client.GetDefaultProjectID() + if exist && req.Organization == nil && req.Project == nil { + req.Project = &defaultProject + } + + defaultOrganization, exist := s.client.GetDefaultOrganizationID() + if exist && req.Organization == nil && req.Project == nil { + req.Organization = &defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if req.Name == "" { + req.Name = namegenerator.GetRandomName("srv") + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreateServerResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteServerRequest struct { + Zone scw.Zone `json:"-"` + + ServerID string `json:"-"` +} + +// DeleteServer: delete a server +// +// Delete a server with the given ID. +func (s *API) DeleteServer(req *DeleteServerRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type GetServerRequest struct { + Zone scw.Zone `json:"-"` + // ServerID: UUID of the server you want to get + ServerID string `json:"-"` +} + +// GetServer: get a server +// +// Get the details of a specified Server. +func (s *API) GetServer(req *GetServerRequest, opts ...scw.RequestOption) (*GetServerResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "", + Headers: http.Header{}, + } + + var resp GetServerResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type setServerRequest struct { + Zone scw.Zone `json:"-"` + // ID: the server unique ID + ID string `json:"-"` + // Name: the server name + Name string `json:"name"` + // Organization: the server organization ID + Organization string `json:"organization"` + // Project: the server project ID + Project string `json:"project"` + // AllowedActions: provide as list of allowed actions on the server + AllowedActions []ServerAction `json:"allowed_actions"` + // Tags: the server associated tags + Tags *[]string `json:"tags"` + // CommercialType: the server commercial type (eg. GP1-M) + CommercialType string `json:"commercial_type"` + // CreationDate: the server creation date + CreationDate *time.Time `json:"creation_date"` + // DynamicIPRequired: true if a dynamic IP is required + DynamicIPRequired bool `json:"dynamic_ip_required"` + // EnableIPv6: true if IPv6 is enabled + EnableIPv6 bool `json:"enable_ipv6"` + // Hostname: the server host name + Hostname string `json:"hostname"` + // Image: provide information on the server image + Image *Image `json:"image"` + // Protected: the server protection option is activated + Protected bool `json:"protected"` + // PrivateIP: the server private IP address + PrivateIP *string `json:"private_ip"` + // PublicIP: information about the public IP + PublicIP *ServerIP `json:"public_ip"` + // ModificationDate: the server modification date + ModificationDate *time.Time `json:"modification_date"` + // State: the server state + // + // Default value: running + State ServerState `json:"state"` + // Location: the server location + Location *ServerLocation `json:"location"` + // IPv6: the server IPv6 address + IPv6 *ServerIPv6 `json:"ipv6"` + // Bootscript: the server bootscript + Bootscript *Bootscript `json:"bootscript"` + // BootType: the server boot type + // + // Default value: local + BootType BootType `json:"boot_type"` + // Volumes: the server volumes + Volumes map[string]*Volume `json:"volumes"` + // SecurityGroup: the server security group + SecurityGroup *SecurityGroupSummary `json:"security_group"` + // Maintenances: the server planned maintenances + Maintenances []*ServerMaintenance `json:"maintenances"` + // StateDetail: the server state_detail + StateDetail string `json:"state_detail"` + // Arch: the server arch + // + // Default value: x86_64 + Arch Arch `json:"arch"` + // PlacementGroup: the server placement group + PlacementGroup *PlacementGroup `json:"placement_group"` + // PrivateNics: the server private NICs + PrivateNics []*PrivateNIC `json:"private_nics"` +} + +func (s *API) setServer(req *setServerRequest, opts ...scw.RequestOption) (*setServerResponse, error) { + var err error + + if req.Project == "" { + defaultProject, _ := s.client.GetDefaultProjectID() + req.Project = defaultProject + } + + if req.Organization == "" { + defaultOrganization, _ := s.client.GetDefaultOrganizationID() + req.Organization = defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ID) == "" { + return nil, errors.New("field ID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PUT", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp setServerResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type UpdateServerRequest struct { + Zone scw.Zone `json:"-"` + // ServerID: UUID of the server + ServerID string `json:"-"` + // Name: name of the server + Name *string `json:"name,omitempty"` + // BootType: + // + // Default value: local + BootType *BootType `json:"boot_type,omitempty"` + // Tags: tags of the server + Tags *[]string `json:"tags,omitempty"` + + Volumes *map[string]*VolumeServerTemplate `json:"volumes,omitempty"` + + Bootscript *string `json:"bootscript,omitempty"` + + DynamicIPRequired *bool `json:"dynamic_ip_required,omitempty"` + + EnableIPv6 *bool `json:"enable_ipv6,omitempty"` + + Protected *bool `json:"protected,omitempty"` + + SecurityGroup *SecurityGroupTemplate `json:"security_group,omitempty"` + // PlacementGroup: placement group ID if server must be part of a placement group + PlacementGroup *NullableStringValue `json:"placement_group,omitempty"` + // PrivateNics: the server private NICs + PrivateNics []*PrivateNIC `json:"private_nics,omitempty"` +} + +// updateServer: update a server +func (s *API) updateServer(req *UpdateServerRequest, opts ...scw.RequestOption) (*UpdateServerResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PATCH", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp UpdateServerResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListServerActionsRequest struct { + Zone scw.Zone `json:"-"` + + ServerID string `json:"-"` +} + +// ListServerActions: list server actions +// +// Liste all actions that can currently be performed on a server. +func (s *API) ListServerActions(req *ListServerActionsRequest, opts ...scw.RequestOption) (*ListServerActionsResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/action", + Headers: http.Header{}, + } + + var resp ListServerActionsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ServerActionRequest struct { + Zone scw.Zone `json:"-"` + // ServerID: UUID of the server + ServerID string `json:"-"` + // Action: the action to perform on the server + // + // Default value: poweron + Action ServerAction `json:"action"` + // Name: the name of the backup you want to create + // + // The name of the backup you want to create. + // This field should only be specified when performing a backup action. + // + Name *string `json:"name,omitempty"` +} + +// ServerAction: perform action +// +// Perform power related actions on a server. Be wary that when terminating a server, all the attached volumes (local *and* block storage) are deleted. So, if you want to keep your local volumes, you must use the `archive` action instead of `terminate`. And if you want to keep block-storage volumes, **you must** detach it beforehand you issue the `terminate` call. For more information, read the [Volumes](#volumes-7e8a39) documentation. +func (s *API) ServerAction(req *ServerActionRequest, opts ...scw.RequestOption) (*ServerActionResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/action", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp ServerActionResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListServerUserDataRequest struct { + Zone scw.Zone `json:"-"` + // ServerID: UUID of the server + ServerID string `json:"-"` +} + +// ListServerUserData: list user data +// +// List all user data keys registered on a given server. +func (s *API) ListServerUserData(req *ListServerUserDataRequest, opts ...scw.RequestOption) (*ListServerUserDataResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/user_data", + Headers: http.Header{}, + } + + var resp ListServerUserDataResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteServerUserDataRequest struct { + Zone scw.Zone `json:"-"` + // ServerID: UUID of the server + ServerID string `json:"-"` + // Key: key of the user data to delete + Key string `json:"-"` +} + +// DeleteServerUserData: delete user data +// +// Delete the given key from a server user data. +func (s *API) DeleteServerUserData(req *DeleteServerUserDataRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return errors.New("field ServerID cannot be empty in request") + } + + if fmt.Sprint(req.Key) == "" { + return errors.New("field Key cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/user_data/" + fmt.Sprint(req.Key) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type ListImagesRequest struct { + Zone scw.Zone `json:"-"` + + Organization *string `json:"-"` + + PerPage *uint32 `json:"-"` + + Page *int32 `json:"-"` + + Name *string `json:"-"` + + Public *bool `json:"-"` + + Arch *string `json:"-"` + + Project *string `json:"-"` + + Tags *string `json:"-"` +} + +// ListImages: list instance images +// +// List all images available in an account. +func (s *API) ListImages(req *ListImagesRequest, opts ...scw.RequestOption) (*ListImagesResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + parameter.AddToQuery(query, "name", req.Name) + parameter.AddToQuery(query, "public", req.Public) + parameter.AddToQuery(query, "arch", req.Arch) + parameter.AddToQuery(query, "project", req.Project) + parameter.AddToQuery(query, "tags", req.Tags) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/images", + Query: query, + Headers: http.Header{}, + } + + var resp ListImagesResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetImageRequest struct { + Zone scw.Zone `json:"-"` + // ImageID: UUID of the image you want to get + ImageID string `json:"-"` +} + +// GetImage: get an instance image +// +// Get details of an image with the given ID. +func (s *API) GetImage(req *GetImageRequest, opts ...scw.RequestOption) (*GetImageResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ImageID) == "" { + return nil, errors.New("field ImageID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/images/" + fmt.Sprint(req.ImageID) + "", + Headers: http.Header{}, + } + + var resp GetImageResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreateImageRequest struct { + Zone scw.Zone `json:"-"` + // Name: name of the image + Name string `json:"name,omitempty"` + // RootVolume: UUID of the snapshot + RootVolume string `json:"root_volume,omitempty"` + // Arch: architecture of the image + // + // Default value: x86_64 + Arch Arch `json:"arch"` + // DefaultBootscript: default bootscript of the image + DefaultBootscript string `json:"default_bootscript,omitempty"` + // ExtraVolumes: additional volumes of the image + ExtraVolumes map[string]*VolumeTemplate `json:"extra_volumes,omitempty"` + // Deprecated: Organization: organization ID of the image + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: project ID of the image + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` + // Tags: the tags of the image + Tags []string `json:"tags,omitempty"` + // Public: true to create a public image + Public bool `json:"public,omitempty"` +} + +// CreateImage: create an instance image +func (s *API) CreateImage(req *CreateImageRequest, opts ...scw.RequestOption) (*CreateImageResponse, error) { + var err error + + defaultProject, exist := s.client.GetDefaultProjectID() + if exist && req.Organization == nil && req.Project == nil { + req.Project = &defaultProject + } + + defaultOrganization, exist := s.client.GetDefaultOrganizationID() + if exist && req.Organization == nil && req.Project == nil { + req.Organization = &defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if req.Name == "" { + req.Name = namegenerator.GetRandomName("img") + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/images", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreateImageResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type SetImageRequest struct { + Zone scw.Zone `json:"-"` + + ID string `json:"-"` + + Name string `json:"name"` + // Arch: + // + // Default value: x86_64 + Arch Arch `json:"arch"` + + CreationDate *time.Time `json:"creation_date"` + + ModificationDate *time.Time `json:"modification_date"` + + DefaultBootscript *Bootscript `json:"default_bootscript"` + + ExtraVolumes map[string]*Volume `json:"extra_volumes"` + + FromServer string `json:"from_server"` + + Organization string `json:"organization"` + + Public bool `json:"public"` + + RootVolume *VolumeSummary `json:"root_volume"` + // State: + // + // Default value: available + State ImageState `json:"state"` + + Project string `json:"project"` + + Tags *[]string `json:"tags"` +} + +// setImage: update image +// +// Replace all image properties with an image message. +func (s *API) setImage(req *SetImageRequest, opts ...scw.RequestOption) (*setImageResponse, error) { + var err error + + if req.Project == "" { + defaultProject, _ := s.client.GetDefaultProjectID() + req.Project = defaultProject + } + + if req.Organization == "" { + defaultOrganization, _ := s.client.GetDefaultOrganizationID() + req.Organization = defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ID) == "" { + return nil, errors.New("field ID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PUT", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/images/" + fmt.Sprint(req.ID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp setImageResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteImageRequest struct { + Zone scw.Zone `json:"-"` + // ImageID: UUID of the image you want to delete + ImageID string `json:"-"` +} + +// DeleteImage: delete an instance image +// +// Delete the image with the given ID. +func (s *API) DeleteImage(req *DeleteImageRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ImageID) == "" { + return errors.New("field ImageID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/images/" + fmt.Sprint(req.ImageID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type ListSnapshotsRequest struct { + Zone scw.Zone `json:"-"` + + Organization *string `json:"-"` + + PerPage *uint32 `json:"-"` + + Page *int32 `json:"-"` + + Name *string `json:"-"` + + Project *string `json:"-"` + + Tags *string `json:"-"` +} + +// ListSnapshots: list snapshots +func (s *API) ListSnapshots(req *ListSnapshotsRequest, opts ...scw.RequestOption) (*ListSnapshotsResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + parameter.AddToQuery(query, "name", req.Name) + parameter.AddToQuery(query, "project", req.Project) + parameter.AddToQuery(query, "tags", req.Tags) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/snapshots", + Query: query, + Headers: http.Header{}, + } + + var resp ListSnapshotsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreateSnapshotRequest struct { + Zone scw.Zone `json:"-"` + // Name: name of the snapshot + Name string `json:"name,omitempty"` + // VolumeID: UUID of the volume + VolumeID string `json:"volume_id,omitempty"` + // Tags: the tags of the snapshot + Tags []string `json:"tags,omitempty"` + // Deprecated: Organization: organization ID of the snapshot + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: project ID of the snapshot + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` +} + +// CreateSnapshot: create a snapshot from a given volume +func (s *API) CreateSnapshot(req *CreateSnapshotRequest, opts ...scw.RequestOption) (*CreateSnapshotResponse, error) { + var err error + + defaultProject, exist := s.client.GetDefaultProjectID() + if exist && req.Organization == nil && req.Project == nil { + req.Project = &defaultProject + } + + defaultOrganization, exist := s.client.GetDefaultOrganizationID() + if exist && req.Organization == nil && req.Project == nil { + req.Organization = &defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if req.Name == "" { + req.Name = namegenerator.GetRandomName("snp") + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/snapshots", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreateSnapshotResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetSnapshotRequest struct { + Zone scw.Zone `json:"-"` + // SnapshotID: UUID of the snapshot you want to get + SnapshotID string `json:"-"` +} + +// GetSnapshot: get a snapshot +// +// Get details of a snapshot with the given ID. +func (s *API) GetSnapshot(req *GetSnapshotRequest, opts ...scw.RequestOption) (*GetSnapshotResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SnapshotID) == "" { + return nil, errors.New("field SnapshotID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/snapshots/" + fmt.Sprint(req.SnapshotID) + "", + Headers: http.Header{}, + } + + var resp GetSnapshotResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type setSnapshotRequest struct { + Zone scw.Zone `json:"-"` + + SnapshotID string `json:"-"` + + ID string `json:"id"` + + Name string `json:"name"` + + Organization string `json:"organization"` + // VolumeType: + // + // Default value: l_ssd + VolumeType VolumeVolumeType `json:"volume_type"` + + Size scw.Size `json:"size"` + // State: + // + // Default value: available + State SnapshotState `json:"state"` + + BaseVolume *SnapshotBaseVolume `json:"base_volume"` + + CreationDate *time.Time `json:"creation_date"` + + ModificationDate *time.Time `json:"modification_date"` + + Project string `json:"project"` + + Tags *[]string `json:"tags"` +} + +// setSnapshot: update snapshot +// +// Replace all snapshot properties with a snapshot message. +func (s *API) setSnapshot(req *setSnapshotRequest, opts ...scw.RequestOption) (*setSnapshotResponse, error) { + var err error + + if req.Project == "" { + defaultProject, _ := s.client.GetDefaultProjectID() + req.Project = defaultProject + } + + if req.Organization == "" { + defaultOrganization, _ := s.client.GetDefaultOrganizationID() + req.Organization = defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SnapshotID) == "" { + return nil, errors.New("field SnapshotID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PUT", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/snapshots/" + fmt.Sprint(req.SnapshotID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp setSnapshotResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteSnapshotRequest struct { + Zone scw.Zone `json:"-"` + // SnapshotID: UUID of the snapshot you want to delete + SnapshotID string `json:"-"` +} + +// DeleteSnapshot: delete a snapshot +// +// Delete the snapshot with the given ID. +func (s *API) DeleteSnapshot(req *DeleteSnapshotRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SnapshotID) == "" { + return errors.New("field SnapshotID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/snapshots/" + fmt.Sprint(req.SnapshotID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type ListVolumesRequest struct { + Zone scw.Zone `json:"-"` + // VolumeType: filter by volume type + // + // Default value: l_ssd + VolumeType *VolumeVolumeType `json:"-"` + // PerPage: a positive integer lower or equal to 100 to select the number of items to return + // + // Default value: 50 + PerPage *uint32 `json:"-"` + // Page: a positive integer to choose the page to return + Page *int32 `json:"-"` + // Organization: filter volume by organization ID + Organization *string `json:"-"` + // Project: filter volume by project ID + Project *string `json:"-"` + // Tags: filter volumes with these exact tags (to filter with several tags, use commas to separate them) + Tags []string `json:"-"` + // Name: filter volume by name (for eg. "vol" will return "myvolume" but not "data") + Name *string `json:"-"` +} + +// ListVolumes: list volumes +func (s *API) ListVolumes(req *ListVolumesRequest, opts ...scw.RequestOption) (*ListVolumesResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "volume_type", req.VolumeType) + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "project", req.Project) + if len(req.Tags) != 0 { + parameter.AddToQuery(query, "tags", strings.Join(req.Tags, ",")) + } + parameter.AddToQuery(query, "name", req.Name) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/volumes", + Query: query, + Headers: http.Header{}, + } + + var resp ListVolumesResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreateVolumeRequest struct { + Zone scw.Zone `json:"-"` + // Name: the volume name + Name string `json:"name,omitempty"` + // Deprecated: Organization: the volume organization ID + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: the volume project ID + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` + // Tags: the volume tags + Tags []string `json:"tags,omitempty"` + // VolumeType: the volume type + // + // Default value: l_ssd + VolumeType VolumeVolumeType `json:"volume_type"` + // Size: the volume disk size + // Precisely one of BaseSnapshot, BaseVolume, Size must be set. + Size *scw.Size `json:"size,omitempty"` + // BaseVolume: the ID of the volume on which this volume will be based + // Precisely one of BaseSnapshot, BaseVolume, Size must be set. + BaseVolume *string `json:"base_volume,omitempty"` + // BaseSnapshot: the ID of the snapshot on which this volume will be based + // Precisely one of BaseSnapshot, BaseVolume, Size must be set. + BaseSnapshot *string `json:"base_snapshot,omitempty"` +} + +// CreateVolume: create a volume +func (s *API) CreateVolume(req *CreateVolumeRequest, opts ...scw.RequestOption) (*CreateVolumeResponse, error) { + var err error + + defaultProject, exist := s.client.GetDefaultProjectID() + if exist && req.Organization == nil && req.Project == nil { + req.Project = &defaultProject + } + + defaultOrganization, exist := s.client.GetDefaultOrganizationID() + if exist && req.Organization == nil && req.Project == nil { + req.Organization = &defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if req.Name == "" { + req.Name = namegenerator.GetRandomName("vol") + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/volumes", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreateVolumeResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetVolumeRequest struct { + Zone scw.Zone `json:"-"` + // VolumeID: UUID of the volume you want to get + VolumeID string `json:"-"` +} + +// GetVolume: get a volume +// +// Get details of a volume with the given ID. +func (s *API) GetVolume(req *GetVolumeRequest, opts ...scw.RequestOption) (*GetVolumeResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.VolumeID) == "" { + return nil, errors.New("field VolumeID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/volumes/" + fmt.Sprint(req.VolumeID) + "", + Headers: http.Header{}, + } + + var resp GetVolumeResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type UpdateVolumeRequest struct { + Zone scw.Zone `json:"-"` + // VolumeID: UUID of the volume + VolumeID string `json:"-"` + // Name: the volume name + Name *string `json:"name,omitempty"` + // Tags: the tags of the volume + Tags *[]string `json:"tags,omitempty"` + // Size: the volume disk size + Size *scw.Size `json:"size,omitempty"` +} + +// UpdateVolume: update a volume +// +// Replace name and/or size properties of given ID volume with the given value(s). Any volume name can be changed while, for now, only `b_ssd` volume growing is supported. +func (s *API) UpdateVolume(req *UpdateVolumeRequest, opts ...scw.RequestOption) (*UpdateVolumeResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.VolumeID) == "" { + return nil, errors.New("field VolumeID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PATCH", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/volumes/" + fmt.Sprint(req.VolumeID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp UpdateVolumeResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteVolumeRequest struct { + Zone scw.Zone `json:"-"` + // VolumeID: UUID of the volume you want to delete + VolumeID string `json:"-"` +} + +// DeleteVolume: delete a volume +// +// Delete the volume with the given ID. +func (s *API) DeleteVolume(req *DeleteVolumeRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.VolumeID) == "" { + return errors.New("field VolumeID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/volumes/" + fmt.Sprint(req.VolumeID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type ListSecurityGroupsRequest struct { + Zone scw.Zone `json:"-"` + // Name: name of the security group + Name *string `json:"-"` + // Organization: the security group organization ID + Organization *string `json:"-"` + // Project: the security group project ID + Project *string `json:"-"` + // Tags: list security groups with these exact tags (to filter with several tags, use commas to separate them) + Tags []string `json:"-"` + // PerPage: a positive integer lower or equal to 100 to select the number of items to return + // + // Default value: 50 + PerPage *uint32 `json:"-"` + // Page: a positive integer to choose the page to return + Page *int32 `json:"-"` +} + +// ListSecurityGroups: list security groups +// +// List all security groups available in an account. +func (s *API) ListSecurityGroups(req *ListSecurityGroupsRequest, opts ...scw.RequestOption) (*ListSecurityGroupsResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "name", req.Name) + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "project", req.Project) + if len(req.Tags) != 0 { + parameter.AddToQuery(query, "tags", strings.Join(req.Tags, ",")) + } + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups", + Query: query, + Headers: http.Header{}, + } + + var resp ListSecurityGroupsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreateSecurityGroupRequest struct { + Zone scw.Zone `json:"-"` + // Name: name of the security group + Name string `json:"name,omitempty"` + // Description: description of the security group + Description string `json:"description,omitempty"` + // Deprecated: Organization: organization ID the security group belongs to + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: project ID the security group belong to + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` + // Tags: the tags of the security group + Tags []string `json:"tags,omitempty"` + // Deprecated: OrganizationDefault: whether this security group becomes the default security group for new instances + // + // Default value: false + // Precisely one of OrganizationDefault, ProjectDefault must be set. + OrganizationDefault *bool `json:"organization_default,omitempty"` + // ProjectDefault: whether this security group becomes the default security group for new instances + // + // Default value: false + // Precisely one of OrganizationDefault, ProjectDefault must be set. + ProjectDefault *bool `json:"project_default,omitempty"` + // Stateful: whether the security group is stateful or not + // + // Default value: false + Stateful bool `json:"stateful,omitempty"` + // InboundDefaultPolicy: default policy for inbound rules + // + // Default value: accept + InboundDefaultPolicy SecurityGroupPolicy `json:"inbound_default_policy"` + // OutboundDefaultPolicy: default policy for outbound rules + // + // Default value: accept + OutboundDefaultPolicy SecurityGroupPolicy `json:"outbound_default_policy"` + // EnableDefaultSecurity: true to block SMTP on IPv4 and IPv6 + EnableDefaultSecurity *bool `json:"enable_default_security,omitempty"` +} + +// CreateSecurityGroup: create a security group +func (s *API) CreateSecurityGroup(req *CreateSecurityGroupRequest, opts ...scw.RequestOption) (*CreateSecurityGroupResponse, error) { + var err error + + defaultProject, exist := s.client.GetDefaultProjectID() + if exist && req.Organization == nil && req.Project == nil { + req.Project = &defaultProject + } + + defaultOrganization, exist := s.client.GetDefaultOrganizationID() + if exist && req.Organization == nil && req.Project == nil { + req.Organization = &defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if req.Name == "" { + req.Name = namegenerator.GetRandomName("sg") + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreateSecurityGroupResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetSecurityGroupRequest struct { + Zone scw.Zone `json:"-"` + // SecurityGroupID: UUID of the security group you want to get + SecurityGroupID string `json:"-"` +} + +// GetSecurityGroup: get a security group +// +// Get the details of a Security Group with the given ID. +func (s *API) GetSecurityGroup(req *GetSecurityGroupRequest, opts ...scw.RequestOption) (*GetSecurityGroupResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return nil, errors.New("field SecurityGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.SecurityGroupID) + "", + Headers: http.Header{}, + } + + var resp GetSecurityGroupResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteSecurityGroupRequest struct { + Zone scw.Zone `json:"-"` + // SecurityGroupID: UUID of the security group you want to delete + SecurityGroupID string `json:"-"` +} + +// DeleteSecurityGroup: delete a security group +func (s *API) DeleteSecurityGroup(req *DeleteSecurityGroupRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return errors.New("field SecurityGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.SecurityGroupID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type setSecurityGroupRequest struct { + Zone scw.Zone `json:"-"` + // ID: the ID of the security group (will be ignored) + ID string `json:"-"` + // Name: the name of the security group + Name string `json:"name"` + // Tags: the tags of the security group + Tags *[]string `json:"tags"` + // CreationDate: the creation date of the security group (will be ignored) + CreationDate *time.Time `json:"creation_date"` + // ModificationDate: the modification date of the security group (will be ignored) + ModificationDate *time.Time `json:"modification_date"` + // Description: the description of the security group + Description string `json:"description"` + // EnableDefaultSecurity: true to block SMTP on IPv4 and IPv6 + EnableDefaultSecurity bool `json:"enable_default_security"` + // InboundDefaultPolicy: the default inbound policy + // + // Default value: accept + InboundDefaultPolicy SecurityGroupPolicy `json:"inbound_default_policy"` + // OutboundDefaultPolicy: the default outbound policy + // + // Default value: accept + OutboundDefaultPolicy SecurityGroupPolicy `json:"outbound_default_policy"` + // Organization: the security groups organization ID + Organization string `json:"organization"` + // Project: the security group project ID + Project string `json:"project"` + // Deprecated: OrganizationDefault: please use project_default instead + OrganizationDefault bool `json:"organization_default"` + // ProjectDefault: true use this security group for future instances created in this project + ProjectDefault bool `json:"project_default"` + // Servers: the servers attached to this security group + Servers []*ServerSummary `json:"servers"` + // Stateful: true to set the security group as stateful + Stateful bool `json:"stateful"` +} + +// setSecurityGroup: update a security group +// +// Replace all security group properties with a security group message. +func (s *API) setSecurityGroup(req *setSecurityGroupRequest, opts ...scw.RequestOption) (*setSecurityGroupResponse, error) { + var err error + + if req.Project == "" { + defaultProject, _ := s.client.GetDefaultProjectID() + req.Project = defaultProject + } + + if req.Organization == "" { + defaultOrganization, _ := s.client.GetDefaultOrganizationID() + req.Organization = defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ID) == "" { + return nil, errors.New("field ID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PUT", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.ID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp setSecurityGroupResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListSecurityGroupRulesRequest struct { + Zone scw.Zone `json:"-"` + // SecurityGroupID: UUID of the security group + SecurityGroupID string `json:"-"` + // PerPage: a positive integer lower or equal to 100 to select the number of items to return + // + // Default value: 50 + PerPage *uint32 `json:"-"` + // Page: a positive integer to choose the page to return + Page *int32 `json:"-"` +} + +// ListSecurityGroupRules: list rules +func (s *API) ListSecurityGroupRules(req *ListSecurityGroupRulesRequest, opts ...scw.RequestOption) (*ListSecurityGroupRulesResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return nil, errors.New("field SecurityGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.SecurityGroupID) + "/rules", + Query: query, + Headers: http.Header{}, + } + + var resp ListSecurityGroupRulesResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreateSecurityGroupRuleRequest struct { + Zone scw.Zone `json:"-"` + // SecurityGroupID: UUID of the security group + SecurityGroupID string `json:"-"` + // Protocol: + // + // Default value: TCP + Protocol SecurityGroupRuleProtocol `json:"protocol"` + // Direction: + // + // Default value: inbound + Direction SecurityGroupRuleDirection `json:"direction"` + // Action: + // + // Default value: accept + Action SecurityGroupRuleAction `json:"action"` + + IPRange scw.IPNet `json:"ip_range,omitempty"` + + DestPortFrom *uint32 `json:"dest_port_from,omitempty"` + + DestPortTo *uint32 `json:"dest_port_to,omitempty"` + + Position uint32 `json:"position,omitempty"` + + Editable bool `json:"editable,omitempty"` +} + +// CreateSecurityGroupRule: create rule +func (s *API) CreateSecurityGroupRule(req *CreateSecurityGroupRuleRequest, opts ...scw.RequestOption) (*CreateSecurityGroupRuleResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return nil, errors.New("field SecurityGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.SecurityGroupID) + "/rules", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreateSecurityGroupRuleResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteSecurityGroupRuleRequest struct { + Zone scw.Zone `json:"-"` + + SecurityGroupID string `json:"-"` + + SecurityGroupRuleID string `json:"-"` +} + +// DeleteSecurityGroupRule: delete rule +// +// Delete a security group rule with the given ID. +func (s *API) DeleteSecurityGroupRule(req *DeleteSecurityGroupRuleRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return errors.New("field SecurityGroupID cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupRuleID) == "" { + return errors.New("field SecurityGroupRuleID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.SecurityGroupID) + "/rules/" + fmt.Sprint(req.SecurityGroupRuleID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type GetSecurityGroupRuleRequest struct { + Zone scw.Zone `json:"-"` + + SecurityGroupID string `json:"-"` + + SecurityGroupRuleID string `json:"-"` +} + +// GetSecurityGroupRule: get rule +// +// Get details of a security group rule with the given ID. +func (s *API) GetSecurityGroupRule(req *GetSecurityGroupRuleRequest, opts ...scw.RequestOption) (*GetSecurityGroupRuleResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return nil, errors.New("field SecurityGroupID cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupRuleID) == "" { + return nil, errors.New("field SecurityGroupRuleID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.SecurityGroupID) + "/rules/" + fmt.Sprint(req.SecurityGroupRuleID) + "", + Headers: http.Header{}, + } + + var resp GetSecurityGroupRuleResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type setSecurityGroupRuleRequest struct { + Zone scw.Zone `json:"-"` + + SecurityGroupID string `json:"-"` + + SecurityGroupRuleID string `json:"-"` + + ID string `json:"id"` + // Protocol: + // + // Default value: TCP + Protocol SecurityGroupRuleProtocol `json:"protocol"` + // Direction: + // + // Default value: inbound + Direction SecurityGroupRuleDirection `json:"direction"` + // Action: + // + // Default value: accept + Action SecurityGroupRuleAction `json:"action"` + + IPRange scw.IPNet `json:"ip_range"` + + DestPortFrom *uint32 `json:"dest_port_from"` + + DestPortTo *uint32 `json:"dest_port_to"` + + Position uint32 `json:"position"` + + Editable bool `json:"editable"` +} + +// setSecurityGroupRule: update security group rule +func (s *API) setSecurityGroupRule(req *setSecurityGroupRuleRequest, opts ...scw.RequestOption) (*setSecurityGroupRuleResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return nil, errors.New("field SecurityGroupID cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupRuleID) == "" { + return nil, errors.New("field SecurityGroupRuleID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PUT", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/security_groups/" + fmt.Sprint(req.SecurityGroupID) + "/rules/" + fmt.Sprint(req.SecurityGroupRuleID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp setSecurityGroupRuleResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListPlacementGroupsRequest struct { + Zone scw.Zone `json:"-"` + // PerPage: a positive integer lower or equal to 100 to select the number of items to return + // + // Default value: 50 + PerPage *uint32 `json:"-"` + // Page: a positive integer to choose the page to return + Page *int32 `json:"-"` + // Organization: list only placement groups of this organization ID + Organization *string `json:"-"` + // Project: list only placement groups of this project ID + Project *string `json:"-"` + // Tags: list placement groups with these exact tags (to filter with several tags, use commas to separate them) + Tags []string `json:"-"` + // Name: filter placement groups by name (for eg. "cluster1" will return "cluster100" and "cluster1" but not "foo") + Name *string `json:"-"` +} + +// ListPlacementGroups: list placement groups +// +// List all placement groups. +func (s *API) ListPlacementGroups(req *ListPlacementGroupsRequest, opts ...scw.RequestOption) (*ListPlacementGroupsResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "project", req.Project) + if len(req.Tags) != 0 { + parameter.AddToQuery(query, "tags", strings.Join(req.Tags, ",")) + } + parameter.AddToQuery(query, "name", req.Name) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups", + Query: query, + Headers: http.Header{}, + } + + var resp ListPlacementGroupsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreatePlacementGroupRequest struct { + Zone scw.Zone `json:"-"` + // Name: name of the placement group + Name string `json:"name,omitempty"` + // Deprecated: Organization: organization ID of the placement group + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: project ID of the placement group + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` + // Tags: the tags of the placement group + Tags []string `json:"tags,omitempty"` + // PolicyMode: the operating mode of the placement group + // + // Default value: optional + PolicyMode PlacementGroupPolicyMode `json:"policy_mode"` + // PolicyType: the policy type of the placement group + // + // Default value: max_availability + PolicyType PlacementGroupPolicyType `json:"policy_type"` +} + +// CreatePlacementGroup: create a placement group +// +// Create a new placement group. +func (s *API) CreatePlacementGroup(req *CreatePlacementGroupRequest, opts ...scw.RequestOption) (*CreatePlacementGroupResponse, error) { + var err error + + defaultProject, exist := s.client.GetDefaultProjectID() + if exist && req.Organization == nil && req.Project == nil { + req.Project = &defaultProject + } + + defaultOrganization, exist := s.client.GetDefaultOrganizationID() + if exist && req.Organization == nil && req.Project == nil { + req.Organization = &defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if req.Name == "" { + req.Name = namegenerator.GetRandomName("pg") + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreatePlacementGroupResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetPlacementGroupRequest struct { + Zone scw.Zone `json:"-"` + // PlacementGroupID: UUID of the placement group you want to get + PlacementGroupID string `json:"-"` +} + +// GetPlacementGroup: get a placement group +// +// Get the given placement group. +func (s *API) GetPlacementGroup(req *GetPlacementGroupRequest, opts ...scw.RequestOption) (*GetPlacementGroupResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.PlacementGroupID) == "" { + return nil, errors.New("field PlacementGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups/" + fmt.Sprint(req.PlacementGroupID) + "", + Headers: http.Header{}, + } + + var resp GetPlacementGroupResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type SetPlacementGroupRequest struct { + Zone scw.Zone `json:"-"` + + PlacementGroupID string `json:"-"` + + Name string `json:"name"` + + Organization string `json:"organization"` + // PolicyMode: + // + // Default value: optional + PolicyMode PlacementGroupPolicyMode `json:"policy_mode"` + // PolicyType: + // + // Default value: max_availability + PolicyType PlacementGroupPolicyType `json:"policy_type"` + + Project string `json:"project"` + + Tags *[]string `json:"tags"` +} + +// SetPlacementGroup: set placement group +// +// Set all parameters of the given placement group. +func (s *API) SetPlacementGroup(req *SetPlacementGroupRequest, opts ...scw.RequestOption) (*SetPlacementGroupResponse, error) { + var err error + + if req.Project == "" { + defaultProject, _ := s.client.GetDefaultProjectID() + req.Project = defaultProject + } + + if req.Organization == "" { + defaultOrganization, _ := s.client.GetDefaultOrganizationID() + req.Organization = defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.PlacementGroupID) == "" { + return nil, errors.New("field PlacementGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PUT", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups/" + fmt.Sprint(req.PlacementGroupID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp SetPlacementGroupResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type UpdatePlacementGroupRequest struct { + Zone scw.Zone `json:"-"` + // PlacementGroupID: UUID of the placement group + PlacementGroupID string `json:"-"` + // Name: name of the placement group + Name *string `json:"name,omitempty"` + // Tags: the tags of the placement group + Tags *[]string `json:"tags,omitempty"` + // PolicyMode: the operating mode of the placement group + // + // Default value: optional + PolicyMode *PlacementGroupPolicyMode `json:"policy_mode,omitempty"` + // PolicyType: the policy type of the placement group + // + // Default value: max_availability + PolicyType *PlacementGroupPolicyType `json:"policy_type,omitempty"` +} + +// UpdatePlacementGroup: update a placement group +// +// Update one or more parameter of the given placement group. +func (s *API) UpdatePlacementGroup(req *UpdatePlacementGroupRequest, opts ...scw.RequestOption) (*UpdatePlacementGroupResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.PlacementGroupID) == "" { + return nil, errors.New("field PlacementGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PATCH", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups/" + fmt.Sprint(req.PlacementGroupID) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp UpdatePlacementGroupResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeletePlacementGroupRequest struct { + Zone scw.Zone `json:"-"` + // PlacementGroupID: UUID of the placement group you want to delete + PlacementGroupID string `json:"-"` +} + +// DeletePlacementGroup: delete the given placement group +// +// Delete the given placement group. +func (s *API) DeletePlacementGroup(req *DeletePlacementGroupRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.PlacementGroupID) == "" { + return errors.New("field PlacementGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups/" + fmt.Sprint(req.PlacementGroupID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type GetPlacementGroupServersRequest struct { + Zone scw.Zone `json:"-"` + + PlacementGroupID string `json:"-"` +} + +// GetPlacementGroupServers: get placement group servers +// +// Get all servers belonging to the given placement group. +func (s *API) GetPlacementGroupServers(req *GetPlacementGroupServersRequest, opts ...scw.RequestOption) (*GetPlacementGroupServersResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.PlacementGroupID) == "" { + return nil, errors.New("field PlacementGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups/" + fmt.Sprint(req.PlacementGroupID) + "/servers", + Headers: http.Header{}, + } + + var resp GetPlacementGroupServersResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type SetPlacementGroupServersRequest struct { + Zone scw.Zone `json:"-"` + + PlacementGroupID string `json:"-"` + + Servers []string `json:"servers"` +} + +// SetPlacementGroupServers: set placement group servers +// +// Set all servers belonging to the given placement group. +func (s *API) SetPlacementGroupServers(req *SetPlacementGroupServersRequest, opts ...scw.RequestOption) (*SetPlacementGroupServersResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.PlacementGroupID) == "" { + return nil, errors.New("field PlacementGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PUT", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups/" + fmt.Sprint(req.PlacementGroupID) + "/servers", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp SetPlacementGroupServersResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type UpdatePlacementGroupServersRequest struct { + Zone scw.Zone `json:"-"` + // PlacementGroupID: UUID of the placement group + PlacementGroupID string `json:"-"` + + Servers []string `json:"servers,omitempty"` +} + +// UpdatePlacementGroupServers: update placement group servers +// +// Update all servers belonging to the given placement group. +func (s *API) UpdatePlacementGroupServers(req *UpdatePlacementGroupServersRequest, opts ...scw.RequestOption) (*UpdatePlacementGroupServersResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.PlacementGroupID) == "" { + return nil, errors.New("field PlacementGroupID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PATCH", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/placement_groups/" + fmt.Sprint(req.PlacementGroupID) + "/servers", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp UpdatePlacementGroupServersResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListIPsRequest struct { + Zone scw.Zone `json:"-"` + // Organization: the organization ID the IPs are reserved in + Organization *string `json:"-"` + // Name: filter on the IP address (Works as a LIKE operation on the IP address) + Name *string `json:"-"` + // PerPage: a positive integer lower or equal to 100 to select the number of items to return + // + // Default value: 50 + PerPage *uint32 `json:"-"` + // Page: a positive integer to choose the page to return + Page *int32 `json:"-"` + // Project: the project ID the IPs are reserved in + Project *string `json:"-"` + // Tags: filter IPs with these exact tags (to filter with several tags, use commas to separate them) + Tags []string `json:"-"` +} + +// ListIPs: list all flexible IPs +func (s *API) ListIPs(req *ListIPsRequest, opts ...scw.RequestOption) (*ListIPsResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "name", req.Name) + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + parameter.AddToQuery(query, "project", req.Project) + if len(req.Tags) != 0 { + parameter.AddToQuery(query, "tags", strings.Join(req.Tags, ",")) + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/ips", + Query: query, + Headers: http.Header{}, + } + + var resp ListIPsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreateIPRequest struct { + Zone scw.Zone `json:"-"` + // Deprecated: Organization: the organization ID the IP is reserved in + // Precisely one of Organization, Project must be set. + Organization *string `json:"organization,omitempty"` + // Project: the project ID the IP is reserved in + // Precisely one of Organization, Project must be set. + Project *string `json:"project,omitempty"` + // Tags: the tags of the IP + Tags []string `json:"tags,omitempty"` + // Server: UUID of the server you want to attach the IP to + Server *string `json:"server,omitempty"` +} + +// CreateIP: reserve a flexible IP +func (s *API) CreateIP(req *CreateIPRequest, opts ...scw.RequestOption) (*CreateIPResponse, error) { + var err error + + defaultProject, exist := s.client.GetDefaultProjectID() + if exist && req.Organization == nil && req.Project == nil { + req.Project = &defaultProject + } + + defaultOrganization, exist := s.client.GetDefaultOrganizationID() + if exist && req.Organization == nil && req.Project == nil { + req.Organization = &defaultOrganization + } + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/ips", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreateIPResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetIPRequest struct { + Zone scw.Zone `json:"-"` + // IP: the IP ID or address to get + IP string `json:"-"` +} + +// GetIP: get a flexible IP +// +// Get details of an IP with the given ID or address. +func (s *API) GetIP(req *GetIPRequest, opts ...scw.RequestOption) (*GetIPResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.IP) == "" { + return nil, errors.New("field IP cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/ips/" + fmt.Sprint(req.IP) + "", + Headers: http.Header{}, + } + + var resp GetIPResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type UpdateIPRequest struct { + Zone scw.Zone `json:"-"` + // IP: IP ID or IP address + IP string `json:"-"` + // Reverse: reverse domain name + Reverse *NullableStringValue `json:"reverse,omitempty"` + // Tags: an array of keywords you want to tag this IP with + Tags *[]string `json:"tags,omitempty"` + + Server *NullableStringValue `json:"server,omitempty"` +} + +// UpdateIP: update a flexible IP +func (s *API) UpdateIP(req *UpdateIPRequest, opts ...scw.RequestOption) (*UpdateIPResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.IP) == "" { + return nil, errors.New("field IP cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PATCH", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/ips/" + fmt.Sprint(req.IP) + "", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp UpdateIPResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeleteIPRequest struct { + Zone scw.Zone `json:"-"` + // IP: the ID or the address of the IP to delete + IP string `json:"-"` +} + +// DeleteIP: delete a flexible IP +// +// Delete the IP with the given ID. +func (s *API) DeleteIP(req *DeleteIPRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.IP) == "" { + return errors.New("field IP cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/ips/" + fmt.Sprint(req.IP) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type ListPrivateNICsRequest struct { + Zone scw.Zone `json:"-"` + + ServerID string `json:"-"` +} + +// ListPrivateNICs: list all private NICs +// +// List all private NICs of a given server. +func (s *API) ListPrivateNICs(req *ListPrivateNICsRequest, opts ...scw.RequestOption) (*ListPrivateNICsResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/private_nics", + Headers: http.Header{}, + } + + var resp ListPrivateNICsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type CreatePrivateNICRequest struct { + Zone scw.Zone `json:"-"` + + ServerID string `json:"-"` + + PrivateNetworkID string `json:"private_network_id,omitempty"` +} + +// CreatePrivateNIC: create a private NIC connecting a server to a private network +// +// Create a private NIC connecting a server to a private network. +func (s *API) CreatePrivateNIC(req *CreatePrivateNICRequest, opts ...scw.RequestOption) (*CreatePrivateNICResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "POST", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/private_nics", + Headers: http.Header{}, + } + + err = scwReq.SetBody(req) + if err != nil { + return nil, err + } + + var resp CreatePrivateNICResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetPrivateNICRequest struct { + Zone scw.Zone `json:"-"` + + ServerID string `json:"-"` + + PrivateNicID string `json:"-"` +} + +// GetPrivateNIC: get a private NIC +// +// Get private NIC properties. +func (s *API) GetPrivateNIC(req *GetPrivateNICRequest, opts ...scw.RequestOption) (*GetPrivateNICResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + if fmt.Sprint(req.PrivateNicID) == "" { + return nil, errors.New("field PrivateNicID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/private_nics/" + fmt.Sprint(req.PrivateNicID) + "", + Headers: http.Header{}, + } + + var resp GetPrivateNICResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type DeletePrivateNICRequest struct { + Zone scw.Zone `json:"-"` + + ServerID string `json:"-"` + + PrivateNicID string `json:"-"` +} + +// DeletePrivateNIC: delete a private NIC +// +// Delete a private NIC. +func (s *API) DeletePrivateNIC(req *DeletePrivateNICRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return errors.New("field ServerID cannot be empty in request") + } + + if fmt.Sprint(req.PrivateNicID) == "" { + return errors.New("field PrivateNicID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "DELETE", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/private_nics/" + fmt.Sprint(req.PrivateNicID) + "", + Headers: http.Header{}, + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + return nil +} + +type ListBootscriptsRequest struct { + Zone scw.Zone `json:"-"` + + Arch *string `json:"-"` + + Title *string `json:"-"` + + Default *bool `json:"-"` + + Public *bool `json:"-"` + + PerPage *uint32 `json:"-"` + + Page *int32 `json:"-"` +} + +// ListBootscripts: list bootscripts +func (s *API) ListBootscripts(req *ListBootscriptsRequest, opts ...scw.RequestOption) (*ListBootscriptsResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "arch", req.Arch) + parameter.AddToQuery(query, "title", req.Title) + parameter.AddToQuery(query, "default", req.Default) + parameter.AddToQuery(query, "public", req.Public) + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/bootscripts", + Query: query, + Headers: http.Header{}, + } + + var resp ListBootscriptsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetBootscriptRequest struct { + Zone scw.Zone `json:"-"` + + BootscriptID string `json:"-"` +} + +// GetBootscript: get bootscripts +// +// Get details of a bootscript with the given ID. +func (s *API) GetBootscript(req *GetBootscriptRequest, opts ...scw.RequestOption) (*GetBootscriptResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.BootscriptID) == "" { + return nil, errors.New("field BootscriptID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/bootscripts/" + fmt.Sprint(req.BootscriptID) + "", + Headers: http.Header{}, + } + + var resp GetBootscriptResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetDashboardRequest struct { + Zone scw.Zone `json:"-"` + + Organization *string `json:"-"` + + Project *string `json:"-"` +} + +func (s *API) GetDashboard(req *GetDashboardRequest, opts ...scw.RequestOption) (*GetDashboardResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + query := url.Values{} + parameter.AddToQuery(query, "organization", req.Organization) + parameter.AddToQuery(query, "project", req.Project) + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/dashboard", + Query: query, + Headers: http.Header{}, + } + + var resp GetDashboardResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListServersResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListServersResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListServersResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.Servers = append(r.Servers, results.Servers...) + r.TotalCount += uint32(len(results.Servers)) + return uint32(len(results.Servers)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListImagesResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListImagesResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListImagesResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.Images = append(r.Images, results.Images...) + r.TotalCount += uint32(len(results.Images)) + return uint32(len(results.Images)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListSnapshotsResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListSnapshotsResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListSnapshotsResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.Snapshots = append(r.Snapshots, results.Snapshots...) + r.TotalCount += uint32(len(results.Snapshots)) + return uint32(len(results.Snapshots)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListVolumesResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListVolumesResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListVolumesResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.Volumes = append(r.Volumes, results.Volumes...) + r.TotalCount += uint32(len(results.Volumes)) + return uint32(len(results.Volumes)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListSecurityGroupsResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListSecurityGroupsResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListSecurityGroupsResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.SecurityGroups = append(r.SecurityGroups, results.SecurityGroups...) + r.TotalCount += uint32(len(results.SecurityGroups)) + return uint32(len(results.SecurityGroups)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListSecurityGroupRulesResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListSecurityGroupRulesResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListSecurityGroupRulesResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.Rules = append(r.Rules, results.Rules...) + r.TotalCount += uint32(len(results.Rules)) + return uint32(len(results.Rules)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListPlacementGroupsResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListPlacementGroupsResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListPlacementGroupsResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.PlacementGroups = append(r.PlacementGroups, results.PlacementGroups...) + r.TotalCount += uint32(len(results.PlacementGroups)) + return uint32(len(results.PlacementGroups)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListIPsResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListIPsResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListIPsResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.IPs = append(r.IPs, results.IPs...) + r.TotalCount += uint32(len(results.IPs)) + return uint32(len(results.IPs)), nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListBootscriptsResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListBootscriptsResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListBootscriptsResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.Bootscripts = append(r.Bootscripts, results.Bootscripts...) + r.TotalCount += uint32(len(results.Bootscripts)) + return uint32(len(results.Bootscripts)), nil +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_utils.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_utils.go new file mode 100644 index 0000000000..6a3133113d --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/instance_utils.go @@ -0,0 +1,332 @@ +package instance + +import ( + "encoding/json" + "fmt" + "sync" + + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +var ( + resourceLock sync.Map +) + +// lockResource locks a resource from a specific resourceID +func lockResource(resourceID string) *sync.Mutex { + v, _ := resourceLock.LoadOrStore(resourceID, &sync.Mutex{}) + mutex := v.(*sync.Mutex) + mutex.Lock() + return mutex +} + +// lockServer locks a server from its zone and its ID +func lockServer(zone scw.Zone, serverID string) *sync.Mutex { + return lockResource(fmt.Sprint("server", zone, serverID)) +} + +// AttachIPRequest contains the parameters to attach an IP to a server +// +// Deprecated: UpdateIPRequest should be used instead +type AttachIPRequest struct { + Zone scw.Zone `json:"-"` + IP string `json:"-"` + ServerID string `json:"server_id"` +} + +// AttachIPResponse contains the updated IP after attaching +// +// Deprecated: UpdateIPResponse should be used instead +type AttachIPResponse struct { + IP *IP +} + +// AttachIP attaches an IP to a server. +// +// Deprecated: UpdateIP() should be used instead +func (s *API) AttachIP(req *AttachIPRequest, opts ...scw.RequestOption) (*AttachIPResponse, error) { + ipResponse, err := s.UpdateIP(&UpdateIPRequest{ + Zone: req.Zone, + IP: req.IP, + Server: &NullableStringValue{Value: req.ServerID}, + }) + if err != nil { + return nil, err + } + + return &AttachIPResponse{IP: ipResponse.IP}, nil +} + +// DetachIPRequest contains the parameters to detach an IP from a server +// +// Deprecated: UpdateIPRequest should be used instead +type DetachIPRequest struct { + Zone scw.Zone `json:"-"` + IP string `json:"-"` +} + +// DetachIPResponse contains the updated IP after detaching +// +// Deprecated: UpdateIPResponse should be used instead +type DetachIPResponse struct { + IP *IP +} + +// DetachIP detaches an IP from a server. +// +// Deprecated: UpdateIP() should be used instead +func (s *API) DetachIP(req *DetachIPRequest, opts ...scw.RequestOption) (*DetachIPResponse, error) { + ipResponse, err := s.UpdateIP(&UpdateIPRequest{ + Zone: req.Zone, + IP: req.IP, + Server: &NullableStringValue{Null: true}, + }) + if err != nil { + return nil, err + } + + return &DetachIPResponse{IP: ipResponse.IP}, nil +} + +// AttachVolumeRequest contains the parameters to attach a volume to a server +type AttachVolumeRequest struct { + Zone scw.Zone `json:"-"` + ServerID string `json:"-"` + VolumeID string `json:"-"` +} + +// AttachVolumeResponse contains the updated server after attaching a volume +type AttachVolumeResponse struct { + Server *Server `json:"-"` +} + +// volumesToVolumeTemplates converts a map of *Volume to a map of *VolumeTemplate +// so it can be used in a UpdateServer request +func volumesToVolumeTemplates(volumes map[string]*VolumeServer) map[string]*VolumeServerTemplate { + volumeTemplates := map[string]*VolumeServerTemplate{} + for key, volume := range volumes { + volumeTemplates[key] = &VolumeServerTemplate{ + ID: volume.ID, + Name: volume.Name, + } + } + return volumeTemplates +} + +// AttachVolume attaches a volume to a server +// +// Note: Implementation is thread-safe. +func (s *API) AttachVolume(req *AttachVolumeRequest, opts ...scw.RequestOption) (*AttachVolumeResponse, error) { + defer lockServer(req.Zone, req.ServerID).Unlock() + // get server with volumes + getServerResponse, err := s.GetServer(&GetServerRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + }) + if err != nil { + return nil, err + } + volumes := getServerResponse.Server.Volumes + + newVolumes := volumesToVolumeTemplates(volumes) + + // add volume to volumes list + // We loop through all the possible volume keys (0 to len(volumes)) + // to find a non existing key and assign it to the requested volume. + // A key should always be found. However we return an error if no keys were found. + found := false + for i := 0; i <= len(volumes); i++ { + key := fmt.Sprintf("%d", i) + if _, ok := newVolumes[key]; !ok { + newVolumes[key] = &VolumeServerTemplate{ + ID: req.VolumeID, + // name is ignored on this PATCH + Name: req.VolumeID, + } + found = true + break + } + } + + if !found { + return nil, fmt.Errorf("could not find key to attach volume %s", req.VolumeID) + } + + // update server + updateServerResponse, err := s.updateServer(&UpdateServerRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + Volumes: &newVolumes, + }) + if err != nil { + return nil, err + } + + return &AttachVolumeResponse{Server: updateServerResponse.Server}, nil +} + +// DetachVolumeRequest contains the parameters to detach a volume from a server +type DetachVolumeRequest struct { + Zone scw.Zone `json:"-"` + VolumeID string `json:"-"` +} + +// DetachVolumeResponse contains the updated server after detaching a volume +type DetachVolumeResponse struct { + Server *Server `json:"-"` +} + +// DetachVolume detaches a volume from a server +// +// Note: Implementation is thread-safe. +func (s *API) DetachVolume(req *DetachVolumeRequest, opts ...scw.RequestOption) (*DetachVolumeResponse, error) { + // get volume + getVolumeResponse, err := s.GetVolume(&GetVolumeRequest{ + Zone: req.Zone, + VolumeID: req.VolumeID, + }) + if err != nil { + return nil, err + } + if getVolumeResponse.Volume == nil { + return nil, errors.New("expected volume to have value in response") + } + if getVolumeResponse.Volume.Server == nil { + return nil, errors.New("volume should be attached to a server") + } + serverID := getVolumeResponse.Volume.Server.ID + + defer lockServer(req.Zone, serverID).Unlock() + // get server with volumes + getServerResponse, err := s.GetServer(&GetServerRequest{ + Zone: req.Zone, + ServerID: serverID, + }) + if err != nil { + return nil, err + } + volumes := getServerResponse.Server.Volumes + // remove volume from volumes list + for key, volume := range volumes { + if volume.ID == req.VolumeID { + delete(volumes, key) + } + } + + newVolumes := volumesToVolumeTemplates(volumes) + + // update server + updateServerResponse, err := s.updateServer(&UpdateServerRequest{ + Zone: req.Zone, + ServerID: serverID, + Volumes: &newVolumes, + }) + if err != nil { + return nil, err + } + + return &DetachVolumeResponse{Server: updateServerResponse.Server}, nil +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListServersResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListBootscriptsResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListIPsResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListSecurityGroupRulesResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListSecurityGroupsResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListServersTypesResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListSnapshotsResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListVolumesResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListImagesResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListServersTypesResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListServersTypesResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListServersTypesResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + if r.Servers == nil { + r.Servers = make(map[string]*ServerType, len(results.Servers)) + } + + for name, serverType := range results.Servers { + r.Servers[name] = serverType + } + + r.TotalCount += uint32(len(results.Servers)) + return uint32(len(results.Servers)), nil +} + +func (v *NullableStringValue) UnmarshalJSON(b []byte) error { + if string(b) == "null" { + v.Null = true + return nil + } + + var tmp string + if err := json.Unmarshal(b, &tmp); err != nil { + return err + } + v.Null = false + v.Value = tmp + return nil +} + +func (v *NullableStringValue) MarshalJSON() ([]byte, error) { + if v.Null { + return []byte("null"), nil + } + return json.Marshal(v.Value) +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/security_group_utils.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/security_group_utils.go new file mode 100644 index 0000000000..2dad4a26cf --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/security_group_utils.go @@ -0,0 +1,218 @@ +package instance + +import ( + "fmt" + + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +// UpdateSecurityGroupRequest contains the parameters to update a security group +type UpdateSecurityGroupRequest struct { + Zone scw.Zone `json:"-"` + SecurityGroupID string `json:"-"` + + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + InboundDefaultPolicy *SecurityGroupPolicy `json:"inbound_default_policy,omitempty"` + OutboundDefaultPolicy *SecurityGroupPolicy `json:"outbound_default_policy,omitempty"` + Stateful *bool `json:"stateful,omitempty"` + OrganizationDefault *bool `json:"organization_default,omitempty"` + ProjectDefault *bool `json:"project_default,omitempty"` + EnableDefaultSecurity *bool `json:"enable_default_security,omitempty"` +} + +type UpdateSecurityGroupResponse struct { + SecurityGroup *SecurityGroup +} + +// UpdateSecurityGroup updates a security group. +func (s *API) UpdateSecurityGroup(req *UpdateSecurityGroupRequest, opts ...scw.RequestOption) (*UpdateSecurityGroupResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SecurityGroupID) == "" { + return nil, errors.New("field SecurityGroupID cannot be empty in request") + } + + getSGResponse, err := s.GetSecurityGroup(&GetSecurityGroupRequest{ + Zone: req.Zone, + SecurityGroupID: req.SecurityGroupID, + }, opts...) + if err != nil { + return nil, err + } + + setRequest := &setSecurityGroupRequest{ + ID: getSGResponse.SecurityGroup.ID, + Name: getSGResponse.SecurityGroup.Name, + Description: getSGResponse.SecurityGroup.Description, + Organization: getSGResponse.SecurityGroup.Organization, + Project: getSGResponse.SecurityGroup.Project, + OrganizationDefault: getSGResponse.SecurityGroup.OrganizationDefault, + ProjectDefault: getSGResponse.SecurityGroup.ProjectDefault, + OutboundDefaultPolicy: getSGResponse.SecurityGroup.OutboundDefaultPolicy, + InboundDefaultPolicy: getSGResponse.SecurityGroup.InboundDefaultPolicy, + Stateful: getSGResponse.SecurityGroup.Stateful, + Zone: req.Zone, + EnableDefaultSecurity: getSGResponse.SecurityGroup.EnableDefaultSecurity, + CreationDate: getSGResponse.SecurityGroup.CreationDate, + ModificationDate: getSGResponse.SecurityGroup.ModificationDate, + Servers: getSGResponse.SecurityGroup.Servers, + } + + // Override the values that need to be updated + if req.Name != nil { + setRequest.Name = *req.Name + } + if req.Description != nil { + setRequest.Description = *req.Description + } + if req.InboundDefaultPolicy != nil { + setRequest.InboundDefaultPolicy = *req.InboundDefaultPolicy + } + if req.OutboundDefaultPolicy != nil { + setRequest.OutboundDefaultPolicy = *req.OutboundDefaultPolicy + } + if req.Stateful != nil { + setRequest.Stateful = *req.Stateful + } + if req.OrganizationDefault != nil { + setRequest.OrganizationDefault = *req.OrganizationDefault + } + if req.ProjectDefault != nil { + setRequest.ProjectDefault = *req.ProjectDefault + } + if req.EnableDefaultSecurity != nil { + setRequest.EnableDefaultSecurity = *req.EnableDefaultSecurity + } + + setRes, err := s.setSecurityGroup(setRequest, opts...) + if err != nil { + return nil, err + } + + return &UpdateSecurityGroupResponse{ + SecurityGroup: setRes.SecurityGroup, + }, nil +} + +// UpdateSecurityGroupRuleRequest contains the parameters to update a security group rule +type UpdateSecurityGroupRuleRequest struct { + Zone scw.Zone `json:"-"` + SecurityGroupID string `json:"-"` + SecurityGroupRuleID string `json:"-"` + + Protocol *SecurityGroupRuleProtocol `json:"protocol"` + Direction *SecurityGroupRuleDirection `json:"direction"` + Action *SecurityGroupRuleAction `json:"action"` + IPRange *scw.IPNet `json:"ip_range"` + Position *uint32 `json:"position"` + + // If set to 0, DestPortFrom will be removed. + // See SecurityGroupRule.DestPortFrom for more information + DestPortFrom *uint32 `json:"dest_port_from"` + + // If set to 0, DestPortTo will be removed. + // See SecurityGroupRule.DestPortTo for more information + DestPortTo *uint32 `json:"dest_port_to"` +} + +type UpdateSecurityGroupRuleResponse struct { + Rule *SecurityGroupRule `json:"security_rule"` +} + +// UpdateSecurityGroupRule updates a security group. +func (s *API) UpdateSecurityGroupRule(req *UpdateSecurityGroupRuleRequest, opts ...scw.RequestOption) (*UpdateSecurityGroupRuleResponse, error) { + var err error + + if fmt.Sprint(req.Zone) == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + res, err := s.GetSecurityGroupRule(&GetSecurityGroupRuleRequest{ + SecurityGroupRuleID: req.SecurityGroupRuleID, + SecurityGroupID: req.SecurityGroupID, + Zone: req.Zone, + }) + if err != nil { + return nil, err + } + + setRequest := &setSecurityGroupRuleRequest{ + Zone: req.Zone, + SecurityGroupID: req.SecurityGroupID, + SecurityGroupRuleID: req.SecurityGroupRuleID, + ID: req.SecurityGroupRuleID, + Direction: res.Rule.Direction, + Protocol: res.Rule.Protocol, + DestPortFrom: res.Rule.DestPortFrom, + DestPortTo: res.Rule.DestPortTo, + IPRange: res.Rule.IPRange, + Action: res.Rule.Action, + Position: res.Rule.Position, + Editable: res.Rule.Editable, + } + + // Override the values that need to be updated + if req.Action != nil { + setRequest.Action = *req.Action + } + if req.IPRange != nil { + setRequest.IPRange = *req.IPRange + } + if req.DestPortTo != nil { + if *req.DestPortTo > 0 { + setRequest.DestPortTo = req.DestPortTo + } else { + setRequest.DestPortTo = nil + } + } + if req.DestPortFrom != nil { + if *req.DestPortFrom > 0 { + setRequest.DestPortFrom = req.DestPortFrom + } else { + setRequest.DestPortFrom = nil + } + } + if req.DestPortFrom != nil && req.DestPortTo != nil && *req.DestPortFrom == *req.DestPortTo { + setRequest.DestPortTo = nil + } + if req.Protocol != nil { + setRequest.Protocol = *req.Protocol + } + if req.Direction != nil { + setRequest.Direction = *req.Direction + } + if req.Position != nil { + setRequest.Position = *req.Position + } + + // When we use ICMP protocol portFrom and portTo should be set to nil + if req.Protocol != nil && *req.Protocol == SecurityGroupRuleProtocolICMP { + setRequest.DestPortFrom = nil + setRequest.DestPortTo = nil + } + + resp, err := s.setSecurityGroupRule(setRequest) + if err != nil { + return nil, err + } + + return &UpdateSecurityGroupRuleResponse{ + Rule: resp.Rule, + }, nil +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/server_utils.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/server_utils.go new file mode 100644 index 0000000000..d0b52157fb --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/server_utils.go @@ -0,0 +1,409 @@ +package instance + +import ( + "bytes" + "fmt" + "io" + "net/http" + "time" + + "github.com/scaleway/scaleway-sdk-go/api/marketplace/v1" + "github.com/scaleway/scaleway-sdk-go/internal/async" + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/scw" + "github.com/scaleway/scaleway-sdk-go/validation" +) + +const ( + defaultTimeout = 5 * time.Minute + defaultRetryInterval = 5 * time.Second +) + +// CreateServer creates a server. +func (s *API) CreateServer(req *CreateServerRequest, opts ...scw.RequestOption) (*CreateServerResponse, error) { + // If image is not a UUID we try to fetch it from marketplace. + if req.Image != "" && !validation.IsUUID(req.Image) { + apiMarketplace := marketplace.NewAPI(s.client) + imageID, err := apiMarketplace.GetLocalImageIDByLabel(&marketplace.GetLocalImageIDByLabelRequest{ + ImageLabel: req.Image, + Zone: req.Zone, + CommercialType: req.CommercialType, + }) + if err != nil { + return nil, err + } + req.Image = imageID + } + + return s.createServer(req, opts...) +} + +// UpdateServer updates a server. +// +// Note: Implementation is thread-safe. +func (s *API) UpdateServer(req *UpdateServerRequest, opts ...scw.RequestOption) (*UpdateServerResponse, error) { + defer lockServer(req.Zone, req.ServerID).Unlock() + return s.updateServer(req, opts...) +} + +// WaitForServerRequest is used by WaitForServer method. +type WaitForServerRequest struct { + ServerID string + Zone scw.Zone + Timeout *time.Duration + RetryInterval *time.Duration +} + +// WaitForServer wait for the server to be in a "terminal state" before returning. +// This function can be used to wait for a server to be started for example. +func (s *API) WaitForServer(req *WaitForServerRequest, opts ...scw.RequestOption) (*Server, error) { + timeout := defaultTimeout + if req.Timeout != nil { + timeout = *req.Timeout + } + retryInterval := defaultRetryInterval + if req.RetryInterval != nil { + retryInterval = *req.RetryInterval + } + + terminalStatus := map[ServerState]struct{}{ + ServerStateStopped: {}, + ServerStateStoppedInPlace: {}, + ServerStateLocked: {}, + ServerStateRunning: {}, + } + + server, err := async.WaitSync(&async.WaitSyncConfig{ + Get: func() (interface{}, bool, error) { + res, err := s.GetServer(&GetServerRequest{ + ServerID: req.ServerID, + Zone: req.Zone, + }, opts...) + + if err != nil { + return nil, false, err + } + _, isTerminal := terminalStatus[res.Server.State] + + return res.Server, isTerminal, err + }, + Timeout: timeout, + IntervalStrategy: async.LinearIntervalStrategy(retryInterval), + }) + if err != nil { + return nil, errors.Wrap(err, "waiting for server failed") + } + return server.(*Server), nil +} + +// ServerActionAndWaitRequest is used by ServerActionAndWait method. +type ServerActionAndWaitRequest struct { + ServerID string + Zone scw.Zone + Action ServerAction + + // Timeout: maximum time to wait before (default: 5 minutes) + Timeout *time.Duration + RetryInterval *time.Duration +} + +// ServerActionAndWait start an action and wait for the server to be in the correct "terminal state" +// expected by this action. +func (s *API) ServerActionAndWait(req *ServerActionAndWaitRequest, opts ...scw.RequestOption) error { + timeout := defaultTimeout + if req.Timeout != nil { + timeout = *req.Timeout + } + retryInterval := defaultRetryInterval + if req.RetryInterval != nil { + retryInterval = *req.RetryInterval + } + + _, err := s.ServerAction(&ServerActionRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + Action: req.Action, + }, opts...) + if err != nil { + return err + } + + finalServer, err := s.WaitForServer(&WaitForServerRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + Timeout: &timeout, + RetryInterval: &retryInterval, + }, opts...) + if err != nil { + return err + } + + // check the action was properly executed + expectedState := ServerState("unknown") + switch req.Action { + case ServerActionPoweron, ServerActionReboot: + expectedState = ServerStateRunning + case ServerActionPoweroff: + expectedState = ServerStateStopped + case ServerActionStopInPlace: + expectedState = ServerStateStoppedInPlace + } + + // backup can be performed from any state + if expectedState != ServerState("unknown") && finalServer.State != expectedState { + return errors.New("expected state %s but found %s: %s", expectedState, finalServer.State, finalServer.StateDetail) + } + + return nil +} + +// GetServerTypeRequest is used by GetServerType. +type GetServerTypeRequest struct { + Zone scw.Zone + Name string +} + +// GetServerType get server type info by it's name. +func (s *API) GetServerType(req *GetServerTypeRequest) (*ServerType, error) { + res, err := s.ListServersTypes(&ListServersTypesRequest{ + Zone: req.Zone, + }, scw.WithAllPages()) + + if err != nil { + return nil, err + } + + if serverType, exist := res.Servers[req.Name]; exist { + return serverType, nil + } + + return nil, errors.New("could not find server type %q", req.Name) +} + +// GetServerUserDataRequest is used by GetServerUserData method. +type GetServerUserDataRequest struct { + Zone scw.Zone `json:"-"` + ServerID string `json:"-"` + + // Key defines the user data key to get. + Key string `json:"-"` +} + +// GetServerUserData gets the content of a user data on a server for the given key. +func (s *API) GetServerUserData(req *GetServerUserDataRequest, opts ...scw.RequestOption) (io.Reader, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + if fmt.Sprint(req.Key) == "" { + return nil, errors.New("field Key cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/user_data/" + fmt.Sprint(req.Key), + Headers: http.Header{}, + } + + res := &bytes.Buffer{} + + err = s.client.Do(scwReq, res, opts...) + if err != nil { + return nil, err + } + + return res, nil +} + +// SetServerUserDataRequest is used by SetServerUserData method. +type SetServerUserDataRequest struct { + Zone scw.Zone `json:"-"` + ServerID string `json:"-"` + + // Key defines the user data key to set. + Key string `json:"-"` + + // Content defines the data to set. + Content io.Reader +} + +// SetServerUserData sets the content of a user data on a server for the given key. +func (s *API) SetServerUserData(req *SetServerUserDataRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return errors.New("field ServerID cannot be empty in request") + } + + if fmt.Sprint(req.Key) == "" { + return errors.New("field Key cannot be empty in request") + } + + if req.Content == nil { + return errors.New("field Content cannot be nil in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "PATCH", + Path: "/instance/v1/zones/" + fmt.Sprint(req.Zone) + "/servers/" + fmt.Sprint(req.ServerID) + "/user_data/" + fmt.Sprint(req.Key), + Headers: http.Header{}, + } + + err = scwReq.SetBody(req.Content) + if err != nil { + return err + } + + err = s.client.Do(scwReq, nil, opts...) + if err != nil { + return err + } + + return nil +} + +// GetAllServerUserDataRequest is used by GetAllServerUserData method. +type GetAllServerUserDataRequest struct { + Zone scw.Zone `json:"-"` + ServerID string `json:"-"` +} + +// GetAllServerUserDataResponse is used by GetAllServerUserData method. +type GetAllServerUserDataResponse struct { + UserData map[string]io.Reader `json:"-"` +} + +// GetAllServerUserData gets all user data on a server. +func (s *API) GetAllServerUserData(req *GetAllServerUserDataRequest, opts ...scw.RequestOption) (*GetAllServerUserDataResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return nil, errors.New("field ServerID cannot be empty in request") + } + + // get all user data keys + allUserDataRes, err := s.ListServerUserData(&ListServerUserDataRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + }) + if err != nil { + return nil, err + } + + res := &GetAllServerUserDataResponse{ + UserData: make(map[string]io.Reader, len(allUserDataRes.UserData)), + } + + // build a map with all user data + for _, key := range allUserDataRes.UserData { + value, err := s.GetServerUserData(&GetServerUserDataRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + Key: key, + }) + if err != nil { + return nil, err + } + res.UserData[key] = value + } + + return res, nil +} + +// SetAllServerUserDataRequest is used by SetAllServerUserData method. +type SetAllServerUserDataRequest struct { + Zone scw.Zone `json:"-"` + ServerID string `json:"-"` + + // UserData defines all user data that will be set to the server. + // This map is idempotent, it means that all the current data will be overwritten and + // all keys not present in this map will be deleted.. All data will be removed if this map is nil. + UserData map[string]io.Reader `json:"-"` +} + +// SetAllServerUserData sets all user data on a server. +func (s *API) SetAllServerUserData(req *SetAllServerUserDataRequest, opts ...scw.RequestOption) error { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.ServerID) == "" { + return errors.New("field ServerID cannot be empty in request") + } + + // get all current user data keys + allUserDataRes, err := s.ListServerUserData(&ListServerUserDataRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + }) + if err != nil { + return err + } + + // delete all current user data + for _, key := range allUserDataRes.UserData { + _, exist := req.UserData[key] + if exist { + continue + } + err := s.DeleteServerUserData(&DeleteServerUserDataRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + Key: key, + }) + if err != nil { + return err + } + } + + // set all new user data + for key, value := range req.UserData { + err := s.SetServerUserData(&SetServerUserDataRequest{ + Zone: req.Zone, + ServerID: req.ServerID, + Key: key, + Content: value, + }) + if err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/snapshot_utils.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/snapshot_utils.go new file mode 100644 index 0000000000..3d93dacf40 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/snapshot_utils.go @@ -0,0 +1,117 @@ +package instance + +import ( + "fmt" + "time" + + "github.com/scaleway/scaleway-sdk-go/internal/async" + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +// WaitForImageRequest is used by WaitForImage method. +type WaitForSnapshotRequest struct { + SnapshotID string + Zone scw.Zone + Timeout *time.Duration + RetryInterval *time.Duration +} + +// WaitForSnapshot wait for the snapshot to be in a "terminal state" before returning. +func (s *API) WaitForSnapshot(req *WaitForSnapshotRequest, opts ...scw.RequestOption) (*Snapshot, error) { + timeout := defaultTimeout + if req.Timeout != nil { + timeout = *req.Timeout + } + retryInterval := defaultRetryInterval + if req.RetryInterval != nil { + retryInterval = *req.RetryInterval + } + + terminalStatus := map[SnapshotState]struct{}{ + SnapshotStateAvailable: {}, + SnapshotStateError: {}, + } + + snapshot, err := async.WaitSync(&async.WaitSyncConfig{ + Get: func() (interface{}, bool, error) { + res, err := s.GetSnapshot(&GetSnapshotRequest{ + SnapshotID: req.SnapshotID, + Zone: req.Zone, + }, opts...) + + if err != nil { + return nil, false, err + } + _, isTerminal := terminalStatus[res.Snapshot.State] + + return res.Snapshot, isTerminal, err + }, + Timeout: timeout, + IntervalStrategy: async.LinearIntervalStrategy(retryInterval), + }) + if err != nil { + return nil, errors.Wrap(err, "waiting for snapshot failed") + } + return snapshot.(*Snapshot), nil +} + +type UpdateSnapshotRequest struct { + Zone scw.Zone + SnapshotID string + Name *string `json:"name,omitempty"` +} + +type UpdateSnapshotResponse struct { + Snapshot *Snapshot +} + +func (s *API) UpdateSnapshot(req *UpdateSnapshotRequest, opts ...scw.RequestOption) (*UpdateSnapshotResponse, error) { + var err error + + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + if fmt.Sprint(req.Zone) == "" { + return nil, errors.New("field Zone cannot be empty in request") + } + + if fmt.Sprint(req.SnapshotID) == "" { + return nil, errors.New("field SnapshotID cannot be empty in request") + } + + getSnapshotResponse, err := s.GetSnapshot(&GetSnapshotRequest{ + Zone: req.Zone, + SnapshotID: req.SnapshotID, + }, opts...) + if err != nil { + return nil, err + } + + setRequest := &setSnapshotRequest{ + SnapshotID: getSnapshotResponse.Snapshot.ID, + Zone: getSnapshotResponse.Snapshot.Zone, + ID: getSnapshotResponse.Snapshot.ID, + Name: getSnapshotResponse.Snapshot.Name, + CreationDate: getSnapshotResponse.Snapshot.CreationDate, + ModificationDate: getSnapshotResponse.Snapshot.ModificationDate, + Organization: getSnapshotResponse.Snapshot.Organization, + Project: getSnapshotResponse.Snapshot.Project, + } + + // Override the values that need to be updated + if req.Name != nil { + setRequest.Name = *req.Name + } + + setRes, err := s.setSnapshot(setRequest, opts...) + if err != nil { + return nil, err + } + + return &UpdateSnapshotResponse{ + Snapshot: setRes.Snapshot, + }, nil +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/volume_utils.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/volume_utils.go new file mode 100644 index 0000000000..710c3b5299 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/instance/v1/volume_utils.go @@ -0,0 +1,56 @@ +package instance + +import ( + "time" + + "github.com/scaleway/scaleway-sdk-go/internal/async" + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +// WaitForImageRequest is used by WaitForImage method. +type WaitForVolumeRequest struct { + VolumeID string + Zone scw.Zone + Timeout *time.Duration + RetryInterval *time.Duration +} + +// WaitForSnapshot wait for the snapshot to be in a "terminal state" before returning. +func (s *API) WaitForVolume(req *WaitForVolumeRequest, opts ...scw.RequestOption) (*Volume, error) { + timeout := defaultTimeout + if req.Timeout != nil { + timeout = *req.Timeout + } + retryInterval := defaultRetryInterval + if req.RetryInterval != nil { + retryInterval = *req.RetryInterval + } + + terminalStatus := map[VolumeState]struct{}{ + VolumeStateAvailable: {}, + VolumeStateError: {}, + } + + volume, err := async.WaitSync(&async.WaitSyncConfig{ + Get: func() (interface{}, bool, error) { + res, err := s.GetVolume(&GetVolumeRequest{ + VolumeID: req.VolumeID, + Zone: req.Zone, + }, opts...) + + if err != nil { + return nil, false, err + } + _, isTerminal := terminalStatus[res.Volume.State] + + return res.Volume, isTerminal, err + }, + Timeout: timeout, + IntervalStrategy: async.LinearIntervalStrategy(retryInterval), + }) + if err != nil { + return nil, errors.Wrap(err, "waiting for volume failed") + } + return volume.(*Volume), nil +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_sdk.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_sdk.go new file mode 100644 index 0000000000..38de054227 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_sdk.go @@ -0,0 +1,304 @@ +// This file was automatically generated. DO NOT EDIT. +// If you have any remark or suggestion do not hesitate to open an issue. + +// Package marketplace provides methods and message types of the marketplace v1 API. +package marketplace + +import ( + "bytes" + "encoding/json" + "fmt" + "net" + "net/http" + "net/url" + "strings" + "time" + + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/internal/marshaler" + "github.com/scaleway/scaleway-sdk-go/internal/parameter" + "github.com/scaleway/scaleway-sdk-go/namegenerator" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +// always import dependencies +var ( + _ fmt.Stringer + _ json.Unmarshaler + _ url.URL + _ net.IP + _ http.Header + _ bytes.Reader + _ time.Time + _ = strings.Join + + _ scw.ScalewayRequest + _ marshaler.Duration + _ scw.File + _ = parameter.AddToQuery + _ = namegenerator.GetRandomName +) + +// API: marketplace API +type API struct { + client *scw.Client +} + +// NewAPI returns a API object from a Scaleway client. +func NewAPI(client *scw.Client) *API { + return &API{ + client: client, + } +} + +type GetImageResponse struct { + Image *Image `json:"image"` +} + +type GetServiceInfoResponse struct { + API string `json:"api"` + + Description string `json:"description"` + + Version string `json:"version"` +} + +type GetVersionResponse struct { + Version *Version `json:"version"` +} + +// Image: image +type Image struct { + // ID: UUID of this image + ID string `json:"id"` + // Name: name of the image + Name string `json:"name"` + // Description: text description of this image + Description string `json:"description"` + // Logo: URL of this image's logo + Logo string `json:"logo"` + // Categories: list of categories this image belongs to + Categories []string `json:"categories"` + // CreationDate: creation date of this image + CreationDate *time.Time `json:"creation_date"` + // ModificationDate: date of the last modification of this image + ModificationDate *time.Time `json:"modification_date"` + // ValidUntil: expiration date of this image + ValidUntil *time.Time `json:"valid_until"` + // Label: label of this image + Label string `json:"label"` + // Versions: list of versions of this image + Versions []*Version `json:"versions"` + // Organization: organization this image belongs to + Organization *Organization `json:"organization"` + + CurrentPublicVersion string `json:"current_public_version"` +} + +type ListImagesResponse struct { + Images []*Image `json:"images"` + + TotalCount uint32 `json:"total_count"` +} + +type ListVersionsResponse struct { + Versions []*Version `json:"versions"` + + TotalCount uint32 `json:"total_count"` +} + +// LocalImage: local image +type LocalImage struct { + // ID: UUID of this local image + ID string `json:"id"` + // CompatibleCommercialTypes: list of all commercial types that are compatible with this local image + CompatibleCommercialTypes []string `json:"compatible_commercial_types"` + // Arch: supported architecture for this local image + Arch string `json:"arch"` + // Zone: availability Zone where this local image is available + Zone scw.Zone `json:"zone"` +} + +type Organization struct { + ID string `json:"id"` + + Name string `json:"name"` +} + +// Version: version +type Version struct { + // ID: UUID of this version + ID string `json:"id"` + // Name: name of this version + Name string `json:"name"` + // CreationDate: creation date of this image version + CreationDate *time.Time `json:"creation_date"` + // ModificationDate: date of the last modification of this version + ModificationDate *time.Time `json:"modification_date"` + // LocalImages: list of local images available in this version + LocalImages []*LocalImage `json:"local_images"` +} + +// Service API + +type GetServiceInfoRequest struct { +} + +func (s *API) GetServiceInfo(req *GetServiceInfoRequest, opts ...scw.RequestOption) (*GetServiceInfoResponse, error) { + var err error + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/marketplace/v1", + Headers: http.Header{}, + } + + var resp GetServiceInfoResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListImagesRequest struct { + // PerPage: a positive integer lower or equal to 100 to select the number of items to display + PerPage *uint32 `json:"-"` + // Page: a positive integer to choose the page to display + Page *int32 `json:"-"` +} + +// ListImages: list marketplace images +func (s *API) ListImages(req *ListImagesRequest, opts ...scw.RequestOption) (*ListImagesResponse, error) { + var err error + + defaultPerPage, exist := s.client.GetDefaultPageSize() + if (req.PerPage == nil || *req.PerPage == 0) && exist { + req.PerPage = &defaultPerPage + } + + query := url.Values{} + parameter.AddToQuery(query, "per_page", req.PerPage) + parameter.AddToQuery(query, "page", req.Page) + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/marketplace/v1/images", + Query: query, + Headers: http.Header{}, + } + + var resp ListImagesResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetImageRequest struct { + // ImageID: display the image name + ImageID string `json:"-"` +} + +// GetImage: get a specific marketplace image +func (s *API) GetImage(req *GetImageRequest, opts ...scw.RequestOption) (*GetImageResponse, error) { + var err error + + if fmt.Sprint(req.ImageID) == "" { + return nil, errors.New("field ImageID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/marketplace/v1/images/" + fmt.Sprint(req.ImageID) + "", + Headers: http.Header{}, + } + + var resp GetImageResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type ListVersionsRequest struct { + ImageID string `json:"-"` +} + +func (s *API) ListVersions(req *ListVersionsRequest, opts ...scw.RequestOption) (*ListVersionsResponse, error) { + var err error + + if fmt.Sprint(req.ImageID) == "" { + return nil, errors.New("field ImageID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/marketplace/v1/images/" + fmt.Sprint(req.ImageID) + "/versions", + Headers: http.Header{}, + } + + var resp ListVersionsResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +type GetVersionRequest struct { + ImageID string `json:"-"` + + VersionID string `json:"-"` +} + +func (s *API) GetVersion(req *GetVersionRequest, opts ...scw.RequestOption) (*GetVersionResponse, error) { + var err error + + if fmt.Sprint(req.ImageID) == "" { + return nil, errors.New("field ImageID cannot be empty in request") + } + + if fmt.Sprint(req.VersionID) == "" { + return nil, errors.New("field VersionID cannot be empty in request") + } + + scwReq := &scw.ScalewayRequest{ + Method: "GET", + Path: "/marketplace/v1/images/" + fmt.Sprint(req.ImageID) + "/versions/" + fmt.Sprint(req.VersionID) + "", + Headers: http.Header{}, + } + + var resp GetVersionResponse + + err = s.client.Do(scwReq, &resp, opts...) + if err != nil { + return nil, err + } + return &resp, nil +} + +// UnsafeGetTotalCount should not be used +// Internal usage only +func (r *ListImagesResponse) UnsafeGetTotalCount() uint32 { + return r.TotalCount +} + +// UnsafeAppend should not be used +// Internal usage only +func (r *ListImagesResponse) UnsafeAppend(res interface{}) (uint32, error) { + results, ok := res.(*ListImagesResponse) + if !ok { + return 0, errors.New("%T type cannot be appended to type %T", res, r) + } + + r.Images = append(r.Images, results.Images...) + r.TotalCount += uint32(len(results.Images)) + return uint32(len(results.Images)), nil +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_utils.go b/vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_utils.go new file mode 100644 index 0000000000..7d999832b6 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/api/marketplace/v1/marketplace_utils.go @@ -0,0 +1,99 @@ +package marketplace + +import ( + "fmt" + "strings" + + "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/scw" +) + +// getLocalImage returns the correct local version of an image matching +// the current zone and the compatible commercial type +func (version *Version) getLocalImage(zone scw.Zone, commercialType string) (*LocalImage, error) { + for _, localImage := range version.LocalImages { + // Check if in correct zone + if localImage.Zone != zone { + continue + } + + // Check if compatible with wanted commercial type + for _, compatibleCommercialType := range localImage.CompatibleCommercialTypes { + if compatibleCommercialType == commercialType { + return localImage, nil + } + } + } + + return nil, fmt.Errorf("couldn't find compatible local image for this image version (%s)", version.ID) +} + +// getLatestVersion returns the current/latest version on an image, +// or an error in case the image doesn't have a public version. +func (image *Image) getLatestVersion() (*Version, error) { + for _, version := range image.Versions { + if version.ID == image.CurrentPublicVersion { + return version, nil + } + } + + return nil, errors.New("latest version could not be found for image %s", image.Label) +} + +// GetLocalImageIDByLabelRequest is used by GetLocalImageIDByLabel +type GetLocalImageIDByLabelRequest struct { + ImageLabel string + Zone scw.Zone + CommercialType string +} + +// GetLocalImageIDByLabel search for an image with the given label (exact match) in the given region +// it returns the latest version of this specific image. +func (s *API) GetLocalImageIDByLabel(req *GetLocalImageIDByLabelRequest, opts ...scw.RequestOption) (string, error) { + if req.Zone == "" { + defaultZone, _ := s.client.GetDefaultZone() + req.Zone = defaultZone + } + + listImageRequest := &ListImagesRequest{} + opts = append(opts, scw.WithAllPages()) + listImageResponse, err := s.ListImages(listImageRequest, opts...) + if err != nil { + return "", err + } + + images := listImageResponse.Images + label := strings.Replace(req.ImageLabel, "-", "_", -1) + commercialType := strings.ToUpper(req.CommercialType) + + for _, image := range images { + // Match label of the image + if label == image.Label { + latestVersion, err := image.getLatestVersion() + if err != nil { + return "", errors.Wrap(err, "couldn't find a matching image for the given label (%s), zone (%s) and commercial type (%s)", req.ImageLabel, req.Zone, req.CommercialType) + } + + localImage, err := latestVersion.getLocalImage(req.Zone, commercialType) + if err != nil { + return "", errors.Wrap(err, "couldn't find a matching image for the given label (%s), zone (%s) and commercial type (%s)", req.ImageLabel, req.Zone, req.CommercialType) + } + + return localImage.ID, nil + } + } + + return "", errors.New("couldn't find a matching image for the given label (%s), zone (%s) and commercial type (%s)", req.ImageLabel, req.Zone, req.CommercialType) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListImagesResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} + +// UnsafeSetTotalCount should not be used +// Internal usage only +func (r *ListVersionsResponse) UnsafeSetTotalCount(totalCount int) { + r.TotalCount = uint32(totalCount) +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/internal/async/wait.go b/vendor/github.com/scaleway/scaleway-sdk-go/internal/async/wait.go new file mode 100644 index 0000000000..7e0d2158fa --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/internal/async/wait.go @@ -0,0 +1,90 @@ +package async + +import ( + "fmt" + "time" +) + +var ( + defaultInterval = time.Second + defaultTimeout = time.Minute * 5 +) + +type IntervalStrategy func() <-chan time.Time + +// WaitSyncConfig defines the waiting options. +type WaitSyncConfig struct { + // This method will be called from another goroutine. + Get func() (value interface{}, isTerminal bool, err error) + IntervalStrategy IntervalStrategy + Timeout time.Duration +} + +// LinearIntervalStrategy defines a linear interval duration. +func LinearIntervalStrategy(interval time.Duration) IntervalStrategy { + return func() <-chan time.Time { + return time.After(interval) + } +} + +// FibonacciIntervalStrategy defines an interval duration who follow the Fibonacci sequence. +func FibonacciIntervalStrategy(base time.Duration, factor float32) IntervalStrategy { + var x, y float32 = 0, 1 + + return func() <-chan time.Time { + x, y = y, x+(y*factor) + return time.After(time.Duration(x) * base) + } +} + +// WaitSync waits and returns when a given stop condition is true or if an error occurs. +func WaitSync(config *WaitSyncConfig) (terminalValue interface{}, err error) { + // initialize configuration + if config.IntervalStrategy == nil { + config.IntervalStrategy = LinearIntervalStrategy(defaultInterval) + } + + if config.Timeout == 0 { + config.Timeout = defaultTimeout + } + + resultValue := make(chan interface{}) + resultErr := make(chan error) + timeout := make(chan bool) + + go func() { + for { + // get the payload + value, stopCondition, err := config.Get() + + // send the payload + if err != nil { + resultErr <- err + return + } + if stopCondition { + resultValue <- value + return + } + + // waiting for an interval before next get() call or a timeout + select { + case <-timeout: + return + case <-config.IntervalStrategy(): + // sleep + } + } + }() + + // waiting for a result or a timeout + select { + case val := <-resultValue: + return val, nil + case err := <-resultErr: + return nil, err + case <-time.After(config.Timeout): + timeout <- true + return nil, fmt.Errorf("timeout after %v", config.Timeout) + } +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/internal/marshaler/duration.go b/vendor/github.com/scaleway/scaleway-sdk-go/internal/marshaler/duration.go new file mode 100644 index 0000000000..0eaf70e56a --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/internal/marshaler/duration.go @@ -0,0 +1,160 @@ +package marshaler + +import ( + "encoding/json" + "time" +) + +// Duration implements a JSON Marshaler to encode a time.Duration in milliseconds. +type Duration int64 + +const milliSec = Duration(time.Millisecond) + +// NewDuration converts a *time.Duration to a *Duration type. +func NewDuration(t *time.Duration) *Duration { + if t == nil { + return nil + } + d := Duration(t.Nanoseconds()) + return &d +} + +// Standard converts a *Duration to a *time.Duration type. +func (d *Duration) Standard() *time.Duration { + return (*time.Duration)(d) +} + +// MarshalJSON encodes the Duration in milliseconds. +func (d Duration) MarshalJSON() ([]byte, error) { + return json.Marshal(int64(d / milliSec)) +} + +// UnmarshalJSON decodes milliseconds to Duration. +func (d *Duration) UnmarshalJSON(b []byte) error { + var tmp int64 + err := json.Unmarshal(b, &tmp) + if err != nil { + return err + } + *d = Duration(tmp) * milliSec + return nil +} + +// DurationSlice is a slice of *Duration +type DurationSlice []*Duration + +// NewDurationSlice converts a []*time.Duration to a DurationSlice type. +func NewDurationSlice(t []*time.Duration) DurationSlice { + ds := make([]*Duration, len(t)) + for i := range ds { + ds[i] = NewDuration(t[i]) + } + return ds +} + +// Standard converts a DurationSlice to a []*time.Duration type. +func (ds *DurationSlice) Standard() []*time.Duration { + t := make([]*time.Duration, len(*ds)) + for i := range t { + t[i] = (*ds)[i].Standard() + } + return t +} + +// Durationint32Map is a int32 map of *Duration +type Durationint32Map map[int32]*Duration + +// NewDurationint32Map converts a map[int32]*time.Duration to a Durationint32Map type. +func NewDurationint32Map(t map[int32]*time.Duration) Durationint32Map { + dm := make(Durationint32Map, len(t)) + for i := range t { + dm[i] = NewDuration(t[i]) + } + return dm +} + +// Standard converts a Durationint32Map to a map[int32]*time.Duration type. +func (dm *Durationint32Map) Standard() map[int32]*time.Duration { + t := make(map[int32]*time.Duration, len(*dm)) + for key, value := range *dm { + t[key] = value.Standard() + } + return t +} + +// LongDuration implements a JSON Marshaler to encode a time.Duration in days. +type LongDuration int64 + +const day = LongDuration(time.Hour) * 24 + +// NewLongDuration converts a *time.Duration to a *LongDuration type. +func NewLongDuration(t *time.Duration) *LongDuration { + if t == nil { + return nil + } + d := LongDuration(t.Nanoseconds()) + return &d +} + +// Standard converts a *LongDuration to a *time.Duration type. +func (d *LongDuration) Standard() *time.Duration { + return (*time.Duration)(d) +} + +// MarshalJSON encodes the LongDuration in days. +func (d LongDuration) MarshalJSON() ([]byte, error) { + return json.Marshal(int64(d / day)) +} + +// UnmarshalJSON decodes days to LongDuration. +func (d *LongDuration) UnmarshalJSON(b []byte) error { + var tmp int64 + err := json.Unmarshal(b, &tmp) + if err != nil { + return err + } + *d = LongDuration(tmp) * day + return nil +} + +// LongDurationSlice is a slice of *LongDuration +type LongDurationSlice []*LongDuration + +// NewLongDurationSlice converts a []*time.Duration to a LongDurationSlice type. +func NewLongDurationSlice(t []*time.Duration) LongDurationSlice { + ds := make([]*LongDuration, len(t)) + for i := range ds { + ds[i] = NewLongDuration(t[i]) + } + return ds +} + +// Standard converts a LongDurationSlice to a []*time.Duration type. +func (ds *LongDurationSlice) Standard() []*time.Duration { + t := make([]*time.Duration, len(*ds)) + for i := range t { + t[i] = (*ds)[i].Standard() + } + return t +} + +// LongDurationint32Map is a int32 map of *LongDuration +type LongDurationint32Map map[int32]*LongDuration + +// NewLongDurationint32Map converts a map[int32]*time.LongDuration to a LongDurationint32Map type. +func NewLongDurationint32Map(t map[int32]*time.Duration) LongDurationint32Map { + dm := make(LongDurationint32Map, len(t)) + for i := range t { + dm[i] = NewLongDuration(t[i]) + } + return dm +} + +// Standard converts a LongDurationint32Map to a map[int32]*time.LongDuration type. +func (dm *LongDurationint32Map) Standard() map[int32]*time.Duration { + t := make(map[int32]*time.Duration, len(*dm)) + for key, value := range *dm { + t[key] = value.Standard() + } + return t +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/internal/parameter/query.go b/vendor/github.com/scaleway/scaleway-sdk-go/internal/parameter/query.go new file mode 100644 index 0000000000..bbb5d11231 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/internal/parameter/query.go @@ -0,0 +1,33 @@ +package parameter + +import ( + "fmt" + "net/url" + "reflect" + "time" +) + +// AddToQuery add a key/value pair to an URL query +func AddToQuery(query url.Values, key string, value interface{}) { + elemValue := reflect.ValueOf(value) + + if elemValue.Kind() == reflect.Invalid || elemValue.Kind() == reflect.Ptr && elemValue.IsNil() { + return + } + + for elemValue.Kind() == reflect.Ptr { + elemValue = reflect.ValueOf(value).Elem() + } + + elemType := elemValue.Type() + switch { + case elemType.Kind() == reflect.Slice: + for i := 0; i < elemValue.Len(); i++ { + query.Add(key, fmt.Sprint(elemValue.Index(i).Interface())) + } + case elemType == reflect.TypeOf(time.Time{}): + query.Add(key, value.(time.Time).Format(time.RFC3339)) + default: + query.Add(key, fmt.Sprint(elemValue.Interface())) + } +} diff --git a/vendor/github.com/scaleway/scaleway-sdk-go/namegenerator/name_generator.go b/vendor/github.com/scaleway/scaleway-sdk-go/namegenerator/name_generator.go new file mode 100644 index 0000000000..11fda45323 --- /dev/null +++ b/vendor/github.com/scaleway/scaleway-sdk-go/namegenerator/name_generator.go @@ -0,0 +1,863 @@ +// Source: github.com/docker/docker/pkg/namesgenerator + +package namegenerator + +import ( + "math/rand" + "strings" + "time" +) + +var r *rand.Rand + +func init() { + source := rand.NewSource(time.Now().UnixNano()) + r = rand.New(source) +} + +var ( + left = [...]string{ + "admiring", + "adoring", + "affectionate", + "agitated", + "amazing", + "angry", + "awesome", + "beautiful", + "blissful", + "bold", + "boring", + "brave", + "busy", + "charming", + "clever", + "cocky", + "cool", + "compassionate", + "competent", + "condescending", + "confident", + "cranky", + "crazy", + "dazzling", + "determined", + "distracted", + "dreamy", + "eager", + "ecstatic", + "elastic", + "elated", + "elegant", + "eloquent", + "epic", + "exciting", + "fervent", + "festive", + "flamboyant", + "focused", + "friendly", + "frosty", + "funny", + "gallant", + "gifted", + "goofy", + "gracious", + "great", + "happy", + "hardcore", + "heuristic", + "hopeful", + "hungry", + "infallible", + "inspiring", + "interesting", + "intelligent", + "jolly", + "jovial", + "keen", + "kind", + "laughing", + "loving", + "lucid", + "magical", + "mystifying", + "modest", + "musing", + "naughty", + "nervous", + "nice", + "nifty", + "nostalgic", + "objective", + "optimistic", + "peaceful", + "pedantic", + "pensive", + "practical", + "priceless", + "quirky", + "quizzical", + "recursing", + "relaxed", + "reverent", + "romantic", + "sad", + "serene", + "sharp", + "silly", + "sleepy", + "stoic", + "strange", + "stupefied", + "suspicious", + "sweet", + "tender", + "thirsty", + "trusting", + "unruffled", + "upbeat", + "vibrant", + "vigilant", + "vigorous", + "wizardly", + "wonderful", + "xenodochial", + "youthful", + "zealous", + "zen", + } + + // Docker, starting from 0.7.x, generates names from notable scientists and hackers. + // Please, for any amazing man that you add to the list, consider adding an equally amazing woman to it, and vice versa. + right = [...]string{ + // Muhammad ibn Jābir al-Ḥarrānī al-Battānī was a founding father of astronomy. https://en.wikipedia.org/wiki/Mu%E1%B8%A5ammad_ibn_J%C4%81bir_al-%E1%B8%A4arr%C4%81n%C4%AB_al-Batt%C4%81n%C4%AB + "albattani", + + // Frances E. Allen, became the first female IBM Fellow in 1989. In 2006, she became the first female recipient of the ACM's Turing Award. https://en.wikipedia.org/wiki/Frances_E._Allen + "allen", + + // June Almeida - Scottish virologist who took the first pictures of the rubella virus - https://en.wikipedia.org/wiki/June_Almeida + "almeida", + + // Kathleen Antonelli, American computer programmer and one of the six original programmers of the ENIAC - https://en.wikipedia.org/wiki/Kathleen_Antonelli + "antonelli", + + // Maria Gaetana Agnesi - Italian mathematician, philosopher, theologian and humanitarian. She was the first woman to write a mathematics handbook and the first woman appointed as a Mathematics Professor at a University. https://en.wikipedia.org/wiki/Maria_Gaetana_Agnesi + "agnesi", + + // Archimedes was a physicist, engineer and mathematician who invented too many things to list them here. https://en.wikipedia.org/wiki/Archimedes + "archimedes", + + // Maria Ardinghelli - Italian translator, mathematician and physicist - https://en.wikipedia.org/wiki/Maria_Ardinghelli + "ardinghelli", + + // Aryabhata - Ancient Indian mathematician-astronomer during 476-550 CE https://en.wikipedia.org/wiki/Aryabhata + "aryabhata", + + // Wanda Austin - Wanda Austin is the President and CEO of The Aerospace Corporation, a leading architect for the US security space programs. https://en.wikipedia.org/wiki/Wanda_Austin + "austin", + + // Charles Babbage invented the concept of a programmable computer. https://en.wikipedia.org/wiki/Charles_Babbage. + "babbage", + + // Stefan Banach - Polish mathematician, was one of the founders of modern functional analysis. https://en.wikipedia.org/wiki/Stefan_Banach + "banach", + + // Buckaroo Banzai and his mentor Dr. Hikita perfectd the "oscillation overthruster", a device that allows one to pass through solid matter. - https://en.wikipedia.org/wiki/The_Adventures_of_Buckaroo_Banzai_Across_the_8th_Dimension + "banzai", + + // John Bardeen co-invented the transistor - https://en.wikipedia.org/wiki/John_Bardeen + "bardeen", + + // Jean Bartik, born Betty Jean Jennings, was one of the original programmers for the ENIAC computer. https://en.wikipedia.org/wiki/Jean_Bartik + "bartik", + + // Laura Bassi, the world's first female professor https://en.wikipedia.org/wiki/Laura_Bassi + "bassi", + + // Hugh Beaver, British engineer, founder of the Guinness Book of World Records https://en.wikipedia.org/wiki/Hugh_Beaver + "beaver", + + // Alexander Graham Bell - an eminent Scottish-born scientist, inventor, engineer and innovator who is credited with inventing the first practical telephone - https://en.wikipedia.org/wiki/Alexander_Graham_Bell + "bell", + + // Karl Friedrich Benz - a German automobile engineer. Inventor of the first practical motorcar. https://en.wikipedia.org/wiki/Karl_Benz + "benz", + + // Homi J Bhabha - was an Indian nuclear physicist, founding director, and professor of physics at the Tata Institute of Fundamental Research. Colloquially known as "father of Indian nuclear programme"- https://en.wikipedia.org/wiki/Homi_J._Bhabha + "bhabha", + + // Bhaskara II - Ancient Indian mathematician-astronomer whose work on calculus predates Newton and Leibniz by over half a millennium - https://en.wikipedia.org/wiki/Bh%C4%81skara_II#Calculus + "bhaskara", + + // Sue Black - British computer scientist and campaigner. She has been instrumental in saving Bletchley Park, the site of World War II codebreaking - https://en.wikipedia.org/wiki/Sue_Black_(computer_scientist) + "black", + + // Elizabeth Helen Blackburn - Australian-American Nobel laureate; best known for co-discovering telomerase. https://en.wikipedia.org/wiki/Elizabeth_Blackburn + "blackburn", + + // Elizabeth Blackwell - American doctor and first American woman to receive a medical degree - https://en.wikipedia.org/wiki/Elizabeth_Blackwell + "blackwell", + + // Niels Bohr is the father of quantum theory. https://en.wikipedia.org/wiki/Niels_Bohr. + "bohr", + + // Kathleen Booth, she's credited with writing the first assembly language. https://en.wikipedia.org/wiki/Kathleen_Booth + "booth", + + // Anita Borg - Anita Borg was the founding director of the Institute for Women and Technology (IWT). https://en.wikipedia.org/wiki/Anita_Borg + "borg", + + // Satyendra Nath Bose - He provided the foundation for Bose–Einstein statistics and the theory of the Bose–Einstein condensate. - https://en.wikipedia.org/wiki/Satyendra_Nath_Bose + "bose", + + // Katherine Louise Bouman is an imaging scientist and Assistant Professor of Computer Science at the California Institute of Technology. She researches computational methods for imaging, and developed an algorithm that made possible the picture first visualization of a black hole using the Event Horizon Telescope. - https://en.wikipedia.org/wiki/Katie_Bouman + "bouman", + + // Evelyn Boyd Granville - She was one of the first African-American woman to receive a Ph.D. in mathematics; she earned it in 1949 from Yale University. https://en.wikipedia.org/wiki/Evelyn_Boyd_Granville + "boyd", + + // Brahmagupta - Ancient Indian mathematician during 598-670 CE who gave rules to compute with zero - https://en.wikipedia.org/wiki/Brahmagupta#Zero + "brahmagupta", + + // Walter Houser Brattain co-invented the transistor - https://en.wikipedia.org/wiki/Walter_Houser_Brattain + "brattain", + + // Emmett Brown invented time travel. https://en.wikipedia.org/wiki/Emmett_Brown (thanks Brian Goff) + "brown", + + // Linda Brown Buck - American biologist and Nobel laureate best known for her genetic and molecular analyses of the mechanisms of smell. https://en.wikipedia.org/wiki/Linda_B._Buck + "buck", + + // Dame Susan Jocelyn Bell Burnell - Northern Irish astrophysicist who discovered radio pulsars and was the first to analyse them. https://en.wikipedia.org/wiki/Jocelyn_Bell_Burnell + "burnell", + + // Annie Jump Cannon - pioneering female astronomer who classified hundreds of thousands of stars and created the system we use to understand stars today. https://en.wikipedia.org/wiki/Annie_Jump_Cannon + "cannon", + + // Rachel Carson - American marine biologist and conservationist, her book Silent Spring and other writings are credited with advancing the global environmental movement. https://en.wikipedia.org/wiki/Rachel_Carson + "carson", + + // Dame Mary Lucy Cartwright - British mathematician who was one of the first to study what is now known as chaos theory. Also known for Cartwright's theorem which finds applications in signal processing. https://en.wikipedia.org/wiki/Mary_Cartwright + "cartwright", + + // Vinton Gray Cerf - American Internet pioneer, recognised as one of "the fathers of the Internet". With Robert Elliot Kahn, he designed TCP and IP, the primary data communication protocols of the Internet and other computer networks. https://en.wikipedia.org/wiki/Vint_Cerf + "cerf", + + // Subrahmanyan Chandrasekhar - Astrophysicist known for his mathematical theory on different stages and evolution in structures of the stars. He has won nobel prize for physics - https://en.wikipedia.org/wiki/Subrahmanyan_Chandrasekhar + "chandrasekhar", + + // Sergey Alexeyevich Chaplygin (Russian: Серге́й Алексе́евич Чаплы́гин; April 5, 1869 – October 8, 1942) was a Russian and Soviet physicist, mathematician, and mechanical engineer. He is known for mathematical formulas such as Chaplygin's equation and for a hypothetical substance in cosmology called Chaplygin gas, named after him. https://en.wikipedia.org/wiki/Sergey_Chaplygin + "chaplygin", + + // Émilie du Châtelet - French natural philosopher, mathematician, physicist, and author during the early 1730s, known for her translation of and commentary on Isaac Newton's book Principia containing basic laws of physics. https://en.wikipedia.org/wiki/%C3%89milie_du_Ch%C3%A2telet + "chatelet", + + // Asima Chatterjee was an Indian organic chemist noted for her research on vinca alkaloids, development of drugs for treatment of epilepsy and malaria - https://en.wikipedia.org/wiki/Asima_Chatterjee + "chatterjee", + + // Pafnuty Chebyshev - Russian mathematician. He is known fo his works on probability, statistics, mechanics, analytical geometry and number theory https://en.wikipedia.org/wiki/Pafnuty_Chebyshev + "chebyshev", + + // Bram Cohen - American computer programmer and author of the BitTorrent peer-to-peer protocol. https://en.wikipedia.org/wiki/Bram_Cohen + "cohen", + + // David Lee Chaum - American computer scientist and cryptographer. Known for his seminal contributions in the field of anonymous communication. https://en.wikipedia.org/wiki/David_Chaum + "chaum", + + // Joan Clarke - Bletchley Park code breaker during the Second World War who pioneered techniques that remained top secret for decades. Also an accomplished numismatist https://en.wikipedia.org/wiki/Joan_Clarke + "clarke", + + // Jane Colden - American botanist widely considered the first female American botanist - https://en.wikipedia.org/wiki/Jane_Colden + "colden", + + // Gerty Theresa Cori - American biochemist who became the third woman—and first American woman—to win a Nobel Prize in science, and the first woman to be awarded the Nobel Prize in Physiology or Medicine. Cori was born in Prague. https://en.wikipedia.org/wiki/Gerty_Cori + "cori", + + // Seymour Roger Cray was an American electrical engineer and supercomputer architect who designed a series of computers that were the fastest in the world for decades. https://en.wikipedia.org/wiki/Seymour_Cray + "cray", + + // This entry reflects a husband and wife team who worked together: + // Joan Curran was a Welsh scientist who developed radar and invented chaff, a radar countermeasure. https://en.wikipedia.org/wiki/Joan_Curran + // Samuel Curran was an Irish physicist who worked alongside his wife during WWII and invented the proximity fuse. https://en.wikipedia.org/wiki/Samuel_Curran + "curran", + + // Marie Curie discovered radioactivity. https://en.wikipedia.org/wiki/Marie_Curie. + "curie", + + // Charles Darwin established the principles of natural evolution. https://en.wikipedia.org/wiki/Charles_Darwin. + "darwin", + + // Leonardo Da Vinci invented too many things to list here. https://en.wikipedia.org/wiki/Leonardo_da_Vinci. + "davinci", + + // A. K. (Alexander Keewatin) Dewdney, Canadian mathematician, computer scientist, author and filmmaker. Contributor to Scientific American's "Computer Recreations" from 1984 to 1991. Author of Core War (program), The Planiverse, The Armchair Universe, The Magic Machine, The New Turing Omnibus, and more. https://en.wikipedia.org/wiki/Alexander_Dewdney + "dewdney", + + // Satish Dhawan - Indian mathematician and aerospace engineer, known for leading the successful and indigenous development of the Indian space programme. https://en.wikipedia.org/wiki/Satish_Dhawan + "dhawan", + + // Bailey Whitfield Diffie - American cryptographer and one of the pioneers of public-key cryptography. https://en.wikipedia.org/wiki/Whitfield_Diffie + "diffie", + + // Edsger Wybe Dijkstra was a Dutch computer scientist and mathematical scientist. https://en.wikipedia.org/wiki/Edsger_W._Dijkstra. + "dijkstra", + + // Paul Adrien Maurice Dirac - English theoretical physicist who made fundamental contributions to the early development of both quantum mechanics and quantum electrodynamics. https://en.wikipedia.org/wiki/Paul_Dirac + "dirac", + + // Agnes Meyer Driscoll - American cryptanalyst during World Wars I and II who successfully cryptanalysed a number of Japanese ciphers. She was also the co-developer of one of the cipher machines of the US Navy, the CM. https://en.wikipedia.org/wiki/Agnes_Meyer_Driscoll + "driscoll", + + // Donna Dubinsky - played an integral role in the development of personal digital assistants (PDAs) serving as CEO of Palm, Inc. and co-founding Handspring. https://en.wikipedia.org/wiki/Donna_Dubinsky + "dubinsky", + + // Annie Easley - She was a leading member of the team which developed software for the Centaur rocket stage and one of the first African-Americans in her field. https://en.wikipedia.org/wiki/Annie_Easley + "easley", + + // Thomas Alva Edison, prolific inventor https://en.wikipedia.org/wiki/Thomas_Edison + "edison", + + // Albert Einstein invented the general theory of relativity. https://en.wikipedia.org/wiki/Albert_Einstein + "einstein", + + // Alexandra Asanovna Elbakyan (Russian: Алекса́ндра Аса́новна Элбакя́н) is a Kazakhstani graduate student, computer programmer, internet pirate in hiding, and the creator of the site Sci-Hub. Nature has listed her in 2016 in the top ten people that mattered in science, and Ars Technica has compared her to Aaron Swartz. - https://en.wikipedia.org/wiki/Alexandra_Elbakyan + "elbakyan", + + // Taher A. ElGamal - Egyptian cryptographer best known for the ElGamal discrete log cryptosystem and the ElGamal digital signature scheme. https://en.wikipedia.org/wiki/Taher_Elgamal + "elgamal", + + // Gertrude Elion - American biochemist, pharmacologist and the 1988 recipient of the Nobel Prize in Medicine - https://en.wikipedia.org/wiki/Gertrude_Elion + "elion", + + // James Henry Ellis - British engineer and cryptographer employed by the GCHQ. Best known for conceiving for the first time, the idea of public-key cryptography. https://en.wikipedia.org/wiki/James_H._Ellis + "ellis", + + // Douglas Engelbart gave the mother of all demos: https://en.wikipedia.org/wiki/Douglas_Engelbart + "engelbart", + + // Euclid invented geometry. https://en.wikipedia.org/wiki/Euclid + "euclid", + + // Leonhard Euler invented large parts of modern mathematics. https://de.wikipedia.org/wiki/Leonhard_Euler + "euler", + + // Michael Faraday - British scientist who contributed to the study of electromagnetism and electrochemistry. https://en.wikipedia.org/wiki/Michael_Faraday + "faraday", + + // Horst Feistel - German-born American cryptographer who was one of the earliest non-government researchers to study the design and theory of block ciphers. Co-developer of DES and Lucifer. Feistel networks, a symmetric structure used in the construction of block ciphers are named after him. https://en.wikipedia.org/wiki/Horst_Feistel + "feistel", + + // Pierre de Fermat pioneered several aspects of modern mathematics. https://en.wikipedia.org/wiki/Pierre_de_Fermat + "fermat", + + // Enrico Fermi invented the first nuclear reactor. https://en.wikipedia.org/wiki/Enrico_Fermi. + "fermi", + + // Richard Feynman was a key contributor to quantum mechanics and particle physics. https://en.wikipedia.org/wiki/Richard_Feynman + "feynman", + + // Benjamin Franklin is famous for his experiments in electricity and the invention of the lightning rod. + "franklin", + + // Yuri Alekseyevich Gagarin - Soviet pilot and cosmonaut, best known as the first human to journey into outer space. https://en.wikipedia.org/wiki/Yuri_Gagarin + "gagarin", + + // Galileo was a founding father of modern astronomy, and faced politics and obscurantism to establish scientific truth. https://en.wikipedia.org/wiki/Galileo_Galilei + "galileo", + + // Évariste Galois - French mathematician whose work laid the foundations of Galois theory and group theory, two major branches of abstract algebra, and the subfield of Galois connections, all while still in his late teens. https://en.wikipedia.org/wiki/%C3%89variste_Galois + "galois", + + // Kadambini Ganguly - Indian physician, known for being the first South Asian female physician, trained in western medicine, to graduate in South Asia. https://en.wikipedia.org/wiki/Kadambini_Ganguly + "ganguly", + + // William Henry "Bill" Gates III is an American business magnate, philanthropist, investor, computer programmer, and inventor. https://en.wikipedia.org/wiki/Bill_Gates + "gates", + + // Johann Carl Friedrich Gauss - German mathematician who made significant contributions to many fields, including number theory, algebra, statistics, analysis, differential geometry, geodesy, geophysics, mechanics, electrostatics, magnetic fields, astronomy, matrix theory, and optics. https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss + "gauss", + + // Marie-Sophie Germain - French mathematician, physicist and philosopher. Known for her work on elasticity theory, number theory and philosophy. https://en.wikipedia.org/wiki/Sophie_Germain + "germain", + + // Adele Goldberg, was one of the designers and developers of the Smalltalk language. https://en.wikipedia.org/wiki/Adele_Goldberg_(computer_scientist) + "goldberg", + + // Adele Goldstine, born Adele Katz, wrote the complete technical description for the first electronic digital computer, ENIAC. https://en.wikipedia.org/wiki/Adele_Goldstine + "goldstine", + + // Shafi Goldwasser is a computer scientist known for creating theoretical foundations of modern cryptography. Winner of 2012 ACM Turing Award. https://en.wikipedia.org/wiki/Shafi_Goldwasser + "goldwasser", + + // James Golick, all around gangster. + "golick", + + // Jane Goodall - British primatologist, ethologist, and anthropologist who is considered to be the world's foremost expert on chimpanzees - https://en.wikipedia.org/wiki/Jane_Goodall + "goodall", + + // Stephen Jay Gould was was an American paleontologist, evolutionary biologist, and historian of science. He is most famous for the theory of punctuated equilibrium - https://en.wikipedia.org/wiki/Stephen_Jay_Gould + "gould", + + // Carolyn Widney Greider - American molecular biologist and joint winner of the 2009 Nobel Prize for Physiology or Medicine for the discovery of telomerase. https://en.wikipedia.org/wiki/Carol_W._Greider + "greider", + + // Alexander Grothendieck - German-born French mathematician who became a leading figure in the creation of modern algebraic geometry. https://en.wikipedia.org/wiki/Alexander_Grothendieck + "grothendieck", + + // Lois Haibt - American computer scientist, part of the team at IBM that developed FORTRAN - https://en.wikipedia.org/wiki/Lois_Haibt + "haibt", + + // Margaret Hamilton - Director of the Software Engineering Division of the MIT Instrumentation Laboratory, which developed on-board flight software for the Apollo space program. https://en.wikipedia.org/wiki/Margaret_Hamilton_(scientist) + "hamilton", + + // Caroline Harriet Haslett - English electrical engineer, electricity industry administrator and champion of women's rights. Co-author of British Standard 1363 that specifies AC power plugs and sockets used across the United Kingdom (which is widely considered as one of the safest designs). https://en.wikipedia.org/wiki/Caroline_Haslett + "haslett", + + // Stephen Hawking pioneered the field of cosmology by combining general relativity and quantum mechanics. https://en.wikipedia.org/wiki/Stephen_Hawking + "hawking", + + // Martin Edward Hellman - American cryptologist, best known for his invention of public-key cryptography in co-operation with Whitfield Diffie and Ralph Merkle. https://en.wikipedia.org/wiki/Martin_Hellman + "hellman", + + // Werner Heisenberg was a founding father of quantum mechanics. https://en.wikipedia.org/wiki/Werner_Heisenberg + "heisenberg", + + // Grete Hermann was a German philosopher noted for her philosophical work on the foundations of quantum mechanics. https://en.wikipedia.org/wiki/Grete_Hermann + "hermann", + + // Caroline Lucretia Herschel - German astronomer and discoverer of several comets. https://en.wikipedia.org/wiki/Caroline_Herschel + "herschel", + + // Heinrich Rudolf Hertz - German physicist who first conclusively proved the existence of the electromagnetic waves. https://en.wikipedia.org/wiki/Heinrich_Hertz + "hertz", + + // Jaroslav Heyrovský was the inventor of the polarographic method, father of the electroanalytical method, and recipient of the Nobel Prize in 1959. His main field of work was polarography. https://en.wikipedia.org/wiki/Jaroslav_Heyrovsk%C3%BD + "heyrovsky", + + // Dorothy Hodgkin was a British biochemist, credited with the development of protein crystallography. She was awarded the Nobel Prize in Chemistry in 1964. https://en.wikipedia.org/wiki/Dorothy_Hodgkin + "hodgkin", + + // Douglas R. Hofstadter is an American professor of cognitive science and author of the Pulitzer Prize and American Book Award-winning work Goedel, Escher, Bach: An Eternal Golden Braid in 1979. A mind-bending work which coined Hofstadter's Law: "It always takes longer than you expect, even when you take into account Hofstadter's Law." https://en.wikipedia.org/wiki/Douglas_Hofstadter + "hofstadter", + + // Erna Schneider Hoover revolutionized modern communication by inventing a computerized telephone switching method. https://en.wikipedia.org/wiki/Erna_Schneider_Hoover + "hoover", + + // Grace Hopper developed the first compiler for a computer programming language and is credited with popularizing the term "debugging" for fixing computer glitches. https://en.wikipedia.org/wiki/Grace_Hopper + "hopper", + + // Frances Hugle, she was an American scientist, engineer, and inventor who contributed to the understanding of semiconductors, integrated circuitry, and the unique electrical principles of microscopic materials. https://en.wikipedia.org/wiki/Frances_Hugle + "hugle", + + // Hypatia - Greek Alexandrine Neoplatonist philosopher in Egypt who was one of the earliest mothers of mathematics - https://en.wikipedia.org/wiki/Hypatia + "hypatia", + + // Teruko Ishizaka - Japanese scientist and immunologist who co-discovered the antibody class Immunoglobulin E. https://en.wikipedia.org/wiki/Teruko_Ishizaka + "ishizaka", + + // Mary Jackson, American mathematician and aerospace engineer who earned the highest title within NASA's engineering department - https://en.wikipedia.org/wiki/Mary_Jackson_(engineer) + "jackson", + + // Yeong-Sil Jang was a Korean scientist and astronomer during the Joseon Dynasty; he invented the first metal printing press and water gauge. https://en.wikipedia.org/wiki/Jang_Yeong-sil + "jang", + + // Betty Jennings - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en.wikipedia.org/wiki/Jean_Bartik + "jennings", + + // Mary Lou Jepsen, was the founder and chief technology officer of One Laptop Per Child (OLPC), and the founder of Pixel Qi. https://en.wikipedia.org/wiki/Mary_Lou_Jepsen + "jepsen", + + // Katherine Coleman Goble Johnson - American physicist and mathematician contributed to the NASA. https://en.wikipedia.org/wiki/Katherine_Johnson + "johnson", + + // Irène Joliot-Curie - French scientist who was awarded the Nobel Prize for Chemistry in 1935. Daughter of Marie and Pierre Curie. https://en.wikipedia.org/wiki/Ir%C3%A8ne_Joliot-Curie + "joliot", + + // Karen Spärck Jones came up with the concept of inverse document frequency, which is used in most search engines today. https://en.wikipedia.org/wiki/Karen_Sp%C3%A4rck_Jones + "jones", + + // A. P. J. Abdul Kalam - is an Indian scientist aka Missile Man of India for his work on the development of ballistic missile and launch vehicle technology - https://en.wikipedia.org/wiki/A._P._J._Abdul_Kalam + "kalam", + + // Sergey Petrovich Kapitsa (Russian: Серге́й Петро́вич Капи́ца; 14 February 1928 – 14 August 2012) was a Russian physicist and demographer. He was best known as host of the popular and long-running Russian scientific TV show, Evident, but Incredible. His father was the Nobel laureate Soviet-era physicist Pyotr Kapitsa, and his brother was the geographer and Antarctic explorer Andrey Kapitsa. - https://en.wikipedia.org/wiki/Sergey_Kapitsa + "kapitsa", + + // Susan Kare, created the icons and many of the interface elements for the original Apple Macintosh in the 1980s, and was an original employee of NeXT, working as the Creative Director. https://en.wikipedia.org/wiki/Susan_Kare + "kare", + + // Mstislav Keldysh - a Soviet scientist in the field of mathematics and mechanics, academician of the USSR Academy of Sciences (1946), President of the USSR Academy of Sciences (1961–1975), three times Hero of Socialist Labor (1956, 1961, 1971), fellow of the Royal Society of Edinburgh (1968). https://en.wikipedia.org/wiki/Mstislav_Keldysh + "keldysh", + + // Mary Kenneth Keller, Sister Mary Kenneth Keller became the first American woman to earn a PhD in Computer Science in 1965. https://en.wikipedia.org/wiki/Mary_Kenneth_Keller + "keller", + + // Johannes Kepler, German astronomer known for his three laws of planetary motion - https://en.wikipedia.org/wiki/Johannes_Kepler + "kepler", + + // Omar Khayyam - Persian mathematician, astronomer and poet. Known for his work on the classification and solution of cubic equations, for his contribution to the understanding of Euclid's fifth postulate and for computing the length of a year very accurately. https://en.wikipedia.org/wiki/Omar_Khayyam + "khayyam", + + // Har Gobind Khorana - Indian-American biochemist who shared the 1968 Nobel Prize for Physiology - https://en.wikipedia.org/wiki/Har_Gobind_Khorana + "khorana", + + // Jack Kilby invented silicone integrated circuits and gave Silicon Valley its name. - https://en.wikipedia.org/wiki/Jack_Kilby + "kilby", + + // Maria Kirch - German astronomer and first woman to discover a comet - https://en.wikipedia.org/wiki/Maria_Margarethe_Kirch + "kirch", + + // Donald Knuth - American computer scientist, author of "The Art of Computer Programming" and creator of the TeX typesetting system. https://en.wikipedia.org/wiki/Donald_Knuth + "knuth", + + // Sophie Kowalevski - Russian mathematician responsible for important original contributions to analysis, differential equations and mechanics - https://en.wikipedia.org/wiki/Sofia_Kovalevskaya + "kowalevski", + + // Marie-Jeanne de Lalande - French astronomer, mathematician and cataloguer of stars - https://en.wikipedia.org/wiki/Marie-Jeanne_de_Lalande + "lalande", + + // Hedy Lamarr - Actress and inventor. The principles of her work are now incorporated into modern Wi-Fi, CDMA and Bluetooth technology. https://en.wikipedia.org/wiki/Hedy_Lamarr + "lamarr", + + // Leslie B. Lamport - American computer scientist. Lamport is best known for his seminal work in distributed systems and was the winner of the 2013 Turing Award. https://en.wikipedia.org/wiki/Leslie_Lamport + "lamport", + + // Mary Leakey - British paleoanthropologist who discovered the first fossilized Proconsul skull - https://en.wikipedia.org/wiki/Mary_Leakey + "leakey", + + // Henrietta Swan Leavitt - she was an American astronomer who discovered the relation between the luminosity and the period of Cepheid variable stars. https://en.wikipedia.org/wiki/Henrietta_Swan_Leavitt + "leavitt", + + // Esther Miriam Zimmer Lederberg - American microbiologist and a pioneer of bacterial genetics. https://en.wikipedia.org/wiki/Esther_Lederberg + "lederberg", + + // Inge Lehmann - Danish seismologist and geophysicist. Known for discovering in 1936 that the Earth has a solid inner core inside a molten outer core. https://en.wikipedia.org/wiki/Inge_Lehmann + "lehmann", + + // Daniel Lewin - Mathematician, Akamai co-founder, soldier, 9/11 victim-- Developed optimization techniques for routing traffic on the internet. Died attempting to stop the 9-11 hijackers. https://en.wikipedia.org/wiki/Daniel_Lewin + "lewin", + + // Ruth Lichterman - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en.wikipedia.org/wiki/Ruth_Teitelbaum + "lichterman", + + // Barbara Liskov - co-developed the Liskov substitution principle. Liskov was also the winner of the Turing Prize in 2008. - https://en.wikipedia.org/wiki/Barbara_Liskov + "liskov", + + // Ada Lovelace invented the first algorithm. https://en.wikipedia.org/wiki/Ada_Lovelace (thanks James Turnbull) + "lovelace", + + // Auguste and Louis Lumière - the first filmmakers in history - https://en.wikipedia.org/wiki/Auguste_and_Louis_Lumi%C3%A8re + "lumiere", + + // Mahavira - Ancient Indian mathematician during 9th century AD who discovered basic algebraic identities - https://en.wikipedia.org/wiki/Mah%C4%81v%C4%ABra_(mathematician) + "mahavira", + + // Lynn Margulis (b. Lynn Petra Alexander) - an American evolutionary theorist and biologist, science author, educator, and popularizer, and was the primary modern proponent for the significance of symbiosis in evolution. - https://en.wikipedia.org/wiki/Lynn_Margulis + "margulis", + + // Yukihiro Matsumoto - Japanese computer scientist and software programmer best known as the chief designer of the Ruby programming language. https://en.wikipedia.org/wiki/Yukihiro_Matsumoto + "matsumoto", + + // James Clerk Maxwell - Scottish physicist, best known for his formulation of electromagnetic theory. https://en.wikipedia.org/wiki/James_Clerk_Maxwell + "maxwell", + + // Maria Mayer - American theoretical physicist and Nobel laureate in Physics for proposing the nuclear shell model of the atomic nucleus - https://en.wikipedia.org/wiki/Maria_Mayer + "mayer", + + // John McCarthy invented LISP: https://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist) + "mccarthy", + + // Barbara McClintock - a distinguished American cytogeneticist, 1983 Nobel Laureate in Physiology or Medicine for discovering transposons. https://en.wikipedia.org/wiki/Barbara_McClintock + "mcclintock", + + // Anne Laura Dorinthea McLaren - British developmental biologist whose work helped lead to human in-vitro fertilisation. https://en.wikipedia.org/wiki/Anne_McLaren + "mclaren", + + // Malcolm McLean invented the modern shipping container: https://en.wikipedia.org/wiki/Malcom_McLean + "mclean", + + // Kay McNulty - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en.wikipedia.org/wiki/Kathleen_Antonelli + "mcnulty", + + // Gregor Johann Mendel - Czech scientist and founder of genetics. https://en.wikipedia.org/wiki/Gregor_Mendel + "mendel", + + // Dmitri Mendeleev - a chemist and inventor. He formulated the Periodic Law, created a farsighted version of the periodic table of elements, and used it to correct the properties of some already discovered elements and also to predict the properties of eight elements yet to be discovered. https://en.wikipedia.org/wiki/Dmitri_Mendeleev + "mendeleev", + + // Lise Meitner - Austrian/Swedish physicist who was involved in the discovery of nuclear fission. The element meitnerium is named after her - https://en.wikipedia.org/wiki/Lise_Meitner + "meitner", + + // Carla Meninsky, was the game designer and programmer for Atari 2600 games Dodge 'Em and Warlords. https://en.wikipedia.org/wiki/Carla_Meninsky + "meninsky", + + // Ralph C. Merkle - American computer scientist, known for devising Merkle's puzzles - one of the very first schemes for public-key cryptography. Also, inventor of Merkle trees and co-inventor of the Merkle-Damgård construction for building collision-resistant cryptographic hash functions and the Merkle-Hellman knapsack cryptosystem. https://en.wikipedia.org/wiki/Ralph_Merkle + "merkle", + + // Johanna Mestorf - German prehistoric archaeologist and first female museum director in Germany - https://en.wikipedia.org/wiki/Johanna_Mestorf + "mestorf", + + // Marvin Minsky - Pioneer in Artificial Intelligence, co-founder of the MIT's AI Lab, won the Turing Award in 1969. https://en.wikipedia.org/wiki/Marvin_Minsky + "minsky", + + // Maryam Mirzakhani - an Iranian mathematician and the first woman to win the Fields Medal. https://en.wikipedia.org/wiki/Maryam_Mirzakhani + "mirzakhani", + + // Gordon Earle Moore - American engineer, Silicon Valley founding father, author of Moore's law. https://en.wikipedia.org/wiki/Gordon_Moore + "moore", + + // Samuel Morse - contributed to the invention of a single-wire telegraph system based on European telegraphs and was a co-developer of the Morse code - https://en.wikipedia.org/wiki/Samuel_Morse + "morse", + + // Ian Murdock - founder of the Debian project - https://en.wikipedia.org/wiki/Ian_Murdock + "murdock", + + // May-Britt Moser - Nobel prize winner neuroscientist who contributed to the discovery of grid cells in the brain. https://en.wikipedia.org/wiki/May-Britt_Moser + "moser", + + // John Napier of Merchiston - Scottish landowner known as an astronomer, mathematician and physicist. Best known for his discovery of logarithms. https://en.wikipedia.org/wiki/John_Napier + "napier", + + // John Forbes Nash, Jr. - American mathematician who made fundamental contributions to game theory, differential geometry, and the study of partial differential equations. https://en.wikipedia.org/wiki/John_Forbes_Nash_Jr. + "nash", + + // John von Neumann - todays computer architectures are based on the von Neumann architecture. https://en.wikipedia.org/wiki/Von_Neumann_architecture + "neumann", + + // Isaac Newton invented classic mechanics and modern optics. https://en.wikipedia.org/wiki/Isaac_Newton + "newton", + + // Xavier Niel - ;) https://en.wikipedia.org/wiki/Xavier_Niel + "niel", + + // Florence Nightingale, more prominently known as a nurse, was also the first female member of the Royal Statistical Society and a pioneer in statistical graphics https://en.wikipedia.org/wiki/Florence_Nightingale#Statistics_and_sanitary_reform + "nightingale", + + // Alfred Nobel - a Swedish chemist, engineer, innovator, and armaments manufacturer (inventor of dynamite) - https://en.wikipedia.org/wiki/Alfred_Nobel + "nobel", + + // Emmy Noether, German mathematician. Noether's Theorem is named after her. https://en.wikipedia.org/wiki/Emmy_Noether + "noether", + + // Poppy Northcutt. Poppy Northcutt was the first woman to work as part of NASA’s Mission Control. http://www.businessinsider.com/poppy-northcutt-helped-apollo-astronauts-2014-12?op=1 + "northcutt", + + // Robert Noyce invented silicone integrated circuits and gave Silicon Valley its name. - https://en.wikipedia.org/wiki/Robert_Noyce + "noyce", + + // Panini - Ancient Indian linguist and grammarian from 4th century CE who worked on the world's first formal system - https://en.wikipedia.org/wiki/P%C4%81%E1%B9%87ini#Comparison_with_modern_formal_systems + "panini", + + // Ambroise Pare invented modern surgery. https://en.wikipedia.org/wiki/Ambroise_Par%C3%A9 + "pare", + + // Blaise Pascal, French mathematician, physicist, and inventor - https://en.wikipedia.org/wiki/Blaise_Pascal + "pascal", + + // Louis Pasteur discovered vaccination, fermentation and pasteurization. https://en.wikipedia.org/wiki/Louis_Pasteur. + "pasteur", + + // Cecilia Payne-Gaposchkin was an astronomer and astrophysicist who, in 1925, proposed in her Ph.D. thesis an explanation for the composition of stars in terms of the relative abundances of hydrogen and helium. https://en.wikipedia.org/wiki/Cecilia_Payne-Gaposchkin + "payne", + + // Radia Perlman is a software designer and network engineer and most famous for her invention of the spanning-tree protocol (STP). https://en.wikipedia.org/wiki/Radia_Perlman + "perlman", + + // Rob Pike was a key contributor to Unix, Plan 9, the X graphic system, utf-8, and the Go programming language. https://en.wikipedia.org/wiki/Rob_Pike + "pike", + + // Henri Poincaré made fundamental contributions in several fields of mathematics. https://en.wikipedia.org/wiki/Henri_Poincar%C3%A9 + "poincare", + + // Laura Poitras is a director and producer whose work, made possible by open source crypto tools, advances the causes of truth and freedom of information by reporting disclosures by whistleblowers such as Edward Snowden. https://en.wikipedia.org/wiki/Laura_Poitras + "poitras", + + // Tat’yana Avenirovna Proskuriakova (Russian: Татья́на Авени́ровна Проскуряко́ва) (January 23 [O.S. January 10] 1909 – August 30, 1985) was a Russian-American Mayanist scholar and archaeologist who contributed significantly to the deciphering of Maya hieroglyphs, the writing system of the pre-Columbian Maya civilization of Mesoamerica. https://en.wikipedia.org/wiki/Tatiana_Proskouriakoff + "proskuriakova", + + // Claudius Ptolemy - a Greco-Egyptian writer of Alexandria, known as a mathematician, astronomer, geographer, astrologer, and poet of a single epigram in the Greek Anthology - https://en.wikipedia.org/wiki/Ptolemy + "ptolemy", + + // C. V. Raman - Indian physicist who won the Nobel Prize in 1930 for proposing the Raman effect. - https://en.wikipedia.org/wiki/C._V._Raman + "raman", + + // Srinivasa Ramanujan - Indian mathematician and autodidact who made extraordinary contributions to mathematical analysis, number theory, infinite series, and continued fractions. - https://en.wikipedia.org/wiki/Srinivasa_Ramanujan + "ramanujan", + + // Sally Kristen Ride was an American physicist and astronaut. She was the first American woman in space, and the youngest American astronaut. https://en.wikipedia.org/wiki/Sally_Ride + "ride", + + // Rita Levi-Montalcini - Won Nobel Prize in Physiology or Medicine jointly with colleague Stanley Cohen for the discovery of nerve growth factor (https://en.wikipedia.org/wiki/Rita_Levi-Montalcini) + "montalcini", + + // Dennis Ritchie - co-creator of UNIX and the C programming language. - https://en.wikipedia.org/wiki/Dennis_Ritchie + "ritchie", + + // Ida Rhodes - American pioneer in computer programming, designed the first computer used for Social Security. https://en.wikipedia.org/wiki/Ida_Rhodes + "rhodes", + + // Julia Hall Bowman Robinson - American mathematician renowned for her contributions to the fields of computability theory and computational complexity theory. https://en.wikipedia.org/wiki/Julia_Robinson + "robinson", + + // Wilhelm Conrad Röntgen - German physicist who was awarded the first Nobel Prize in Physics in 1901 for the discovery of X-rays (Röntgen rays). https://en.wikipedia.org/wiki/Wilhelm_R%C3%B6ntgen + "roentgen", + + // Rosalind Franklin - British biophysicist and X-ray crystallographer whose research was critical to the understanding of DNA - https://en.wikipedia.org/wiki/Rosalind_Franklin + "rosalind", + + // Vera Rubin - American astronomer who pioneered work on galaxy rotation rates. https://en.wikipedia.org/wiki/Vera_Rubin + "rubin", + + // Meghnad Saha - Indian astrophysicist best known for his development of the Saha equation, used to describe chemical and physical conditions in stars - https://en.wikipedia.org/wiki/Meghnad_Saha + "saha", + + // Jean E. Sammet developed FORMAC, the first widely used computer language for symbolic manipulation of mathematical formulas. https://en.wikipedia.org/wiki/Jean_E._Sammet + "sammet", + + // Mildred Sanderson - American mathematician best known for Sanderson's theorem concerning modular invariants. https://en.wikipedia.org/wiki/Mildred_Sanderson + "sanderson", + + // Satoshi Nakamoto is the name used by the unknown person or group of people who developed bitcoin, authored the bitcoin white paper, and created and deployed bitcoin's original reference implementation. https://en.wikipedia.org/wiki/Satoshi_Nakamoto + "satoshi", + + // Adi Shamir - Israeli cryptographer whose numerous inventions and contributions to cryptography include the Ferge Fiat Shamir identification scheme, the Rivest Shamir Adleman (RSA) public-key cryptosystem, the Shamir's secret sharing scheme, the breaking of the Merkle-Hellman cryptosystem, the TWINKLE and TWIRL factoring devices and the discovery of differential cryptanalysis (with Eli Biham). https://en.wikipedia.org/wiki/Adi_Shamir + "shamir", + + // Claude Shannon - The father of information theory and founder of digital circuit design theory. (https://en.wikipedia.org/wiki/Claude_Shannon) + "shannon", + + // Carol Shaw - Originally an Atari employee, Carol Shaw is said to be the first female video game designer. https://en.wikipedia.org/wiki/Carol_Shaw_(video_game_designer) + "shaw", + + // Dame Stephanie "Steve" Shirley - Founded a software company in 1962 employing women working from home. https://en.wikipedia.org/wiki/Steve_Shirley + "shirley", + + // William Shockley co-invented the transistor - https://en.wikipedia.org/wiki/William_Shockley + "shockley", + + // Lina Solomonovna Stern (or Shtern; Russian: Лина Соломоновна Штерн; 26 August 1878 – 7 March 1968) was a Soviet biochemist, physiologist and humanist whose medical discoveries saved thousands of lives at the fronts of World War II. She is best known for her pioneering work on blood–brain barrier, which she described as hemato-encephalic barrier in 1921. https://en.wikipedia.org/wiki/Lina_Stern + "shtern", + + // Françoise Barré-Sinoussi - French virologist and Nobel Prize Laureate in Physiology or Medicine; her work was fundamental in identifying HIV as the cause of AIDS. https://en.wikipedia.org/wiki/Fran%C3%A7oise_Barr%C3%A9-Sinoussi + "sinoussi", + + // Betty Snyder - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en.wikipedia.org/wiki/Betty_Holberton + "snyder", + + // Cynthia Solomon - Pioneer in the fields of artificial intelligence, computer science and educational computing. Known for creation of Logo, an educational programming language. https://en.wikipedia.org/wiki/Cynthia_Solomon + "solomon", + + // Frances Spence - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en.wikipedia.org/wiki/Frances_Spence + "spence", + + // Richard Matthew Stallman - the founder of the Free Software movement, the GNU project, the Free Software Foundation, and the League for Programming Freedom. He also invented the concept of copyleft to protect the ideals of this movement, and enshrined this concept in the widely-used GPL (General Public License) for software. https://en.wikiquote.org/wiki/Richard_Stallman + "stallman", + + // Michael Stonebraker is a database research pioneer and architect of Ingres, Postgres, VoltDB and SciDB. Winner of 2014 ACM Turing Award. https://en.wikipedia.org/wiki/Michael_Stonebraker + "stonebraker", + + // Ivan Edward Sutherland - American computer scientist and Internet pioneer, widely regarded as the father of computer graphics. https://en.wikipedia.org/wiki/Ivan_Sutherland + "sutherland", + + // Janese Swanson (with others) developed the first of the Carmen Sandiego games. She went on to found Girl Tech. https://en.wikipedia.org/wiki/Janese_Swanson + "swanson", + + // Aaron Swartz was influential in creating RSS, Markdown, Creative Commons, Reddit, and much of the internet as we know it today. He was devoted to freedom of information on the web. https://en.wikiquote.org/wiki/Aaron_Swartz + "swartz", + + // Bertha Swirles was a theoretical physicist who made a number of contributions to early quantum theory. https://en.wikipedia.org/wiki/Bertha_Swirles + "swirles", + + // Helen Brooke Taussig - American cardiologist and founder of the field of paediatric cardiology. https://en.wikipedia.org/wiki/Helen_B._Taussig + "taussig", + + // Valentina Tereshkova is a Russian engineer, cosmonaut and politician. She was the first woman to fly to space in 1963. In 2013, at the age of 76, she offered to go on a one-way mission to Mars. https://en.wikipedia.org/wiki/Valentina_Tereshkova + "tereshkova", + + // Nikola Tesla invented the AC electric system and every gadget ever used by a James Bond villain. https://en.wikipedia.org/wiki/Nikola_Tesla + "tesla", + + // Marie Tharp - American geologist and oceanic cartographer who co-created the first scientific map of the Atlantic Ocean floor. Her work led to the acceptance of the theories of plate tectonics and continental drift. https://en.wikipedia.org/wiki/Marie_Tharp + "tharp", + + // Ken Thompson - co-creator of UNIX and the C programming language - https://en.wikipedia.org/wiki/Ken_Thompson + "thompson", + + // Linus Torvalds invented Linux and Git. https://en.wikipedia.org/wiki/Linus_Torvalds + "torvalds", + + // Youyou Tu - Chinese pharmaceutical chemist and educator known for discovering artemisinin and dihydroartemisinin, used to treat malaria, which has saved millions of lives. Joint winner of the 2015 Nobel Prize in Physiology or Medicine. https://en.wikipedia.org/wiki/Tu_Youyou + "tu", + + // Alan Turing was a founding father of computer science. https://en.wikipedia.org/wiki/Alan_Turing. + "turing", + + // Varahamihira - Ancient Indian mathematician who discovered trigonometric formulae during 505-587 CE - https://en.wikipedia.org/wiki/Var%C4%81hamihira#Contributions + "varahamihira", + + // Dorothy Vaughan was a NASA mathematician and computer programmer on the SCOUT launch vehicle program that put America's first satellites into space - https://en.wikipedia.org/wiki/Dorothy_Vaughan + "vaughan", + + // Sir Mokshagundam Visvesvaraya - is a notable Indian engineer. He is a recipient of the Indian Republic's highest honour, the Bharat Ratna, in 1955. On his birthday, 15 September is celebrated as Engineer's Day in India in his memory - https://en.wikipedia.org/wiki/Visvesvaraya + "visvesvaraya", + + // Christiane Nüsslein-Volhard - German biologist, won Nobel Prize in Physiology or Medicine in 1995 for research on the genetic control of embryonic development. https://en.wikipedia.org/wiki/Christiane_N%C3%BCsslein-Volhard + "volhard", + + // Cédric Villani - French mathematician, won Fields Medal, Fermat Prize and Poincaré Price for his work in differential geometry and statistical mechanics. https://en.wikipedia.org/wiki/C%C3%A9dric_Villani + "villani", + + // Marlyn Wescoff - one of the original programmers of the ENIAC. https://en.wikipedia.org/wiki/ENIAC - https://en.wikipedia.org/wiki/Marlyn_Meltzer + "wescoff", + + // Sylvia B. Wilbur - British computer scientist who helped develop the ARPANET, was one of the first to exchange email in the UK and a leading researcher in computer-supported collaborative work. https://en.wikipedia.org/wiki/Sylvia_Wilbur + "wilbur", + + // Andrew Wiles - Notable British mathematician who proved the enigmatic Fermat's Last Theorem - https://en.wikipedia.org/wiki/Andrew_Wiles + "wiles", + + // Roberta Williams, did pioneering work in graphical adventure games for personal computers, particularly the King's Quest series. https://en.wikipedia.org/wiki/Roberta_Williams + "williams", + + // Malcolm John Williamson - British mathematician and cryptographer employed by the GCHQ. Developed in 1974 what is now known as Diffie-Hellman key exchange (Diffie and Hellman first published the scheme in 1976). https://en.wikipedia.org/wiki/Malcolm_J._Williamson + "williamson", + + // Sophie Wilson designed the first Acorn Micro-Computer and the instruction set for ARM processors. https://en.wikipedia.org/wiki/Sophie_Wilson + "wilson", + + // Jeannette Wing - co-developed the Liskov substitution principle. - https://en.wikipedia.org/wiki/Jeannette_Wing + "wing", + + // Steve Wozniak invented the Apple I and Apple II. https://en.wikipedia.org/wiki/Steve_Wozniak + "wozniak", + + // The Wright brothers, Orville and Wilbur - credited with inventing and building the world's first successful airplane and making the first controlled, powered and sustained heavier-than-air human flight - https://en.wikipedia.org/wiki/Wright_brothers + "wright", + + // Chien-Shiung Wu - Chinese-American experimental physicist who made significant contributions to nuclear physics. https://en.wikipedia.org/wiki/Chien-Shiung_Wu + "wu", + + // Rosalyn Sussman Yalow - Rosalyn Sussman Yalow was an American medical physicist, and a co-winner of the 1977 Nobel Prize in Physiology or Medicine for development of the radioimmunoassay technique. https://en.wikipedia.org/wiki/Rosalyn_Sussman_Yalow + "yalow", + + // Ada Yonath - an Israeli crystallographer, the first woman from the Middle East to win a Nobel prize in the sciences. https://en.wikipedia.org/wiki/Ada_Yonath + "yonath", + + // Nikolay Yegorovich Zhukovsky (Russian: Никола́й Его́рович Жуко́вский, January 17 1847 – March 17, 1921) was a Russian scientist, mathematician and engineer, and a founding father of modern aero- and hydrodynamics. Whereas contemporary scientists scoffed at the idea of human flight, Zhukovsky was the first to undertake the study of airflow. He is often called the Father of Russian Aviation. https://en.wikipedia.org/wiki/Nikolay_Yegorovich_Zhukovsky + "zhukovsky", + } +) + +// GetRandomName generates a random name from the list of adjectives and surnames in this package +// formatted as "scw-adjective-surname". For example 'scw-focused-turing'. +func GetRandomName(prefixes ...string) string { +begin: + parts := append(prefixes, left[r.Intn(len(left))], right[r.Intn(len(right))]) + name := strings.Join(parts, "-") + if strings.Contains(name, "boring-wozniak") /* Steve Wozniak is not boring */ { + goto begin + } + + return name +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d5cada7294..b369a037a9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -819,9 +819,15 @@ github.com/ryanuber/go-glob github.com/sahilm/fuzzy # github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9 ## explicit; go 1.17 +github.com/scaleway/scaleway-sdk-go/api/instance/v1 +github.com/scaleway/scaleway-sdk-go/api/marketplace/v1 +github.com/scaleway/scaleway-sdk-go/internal/async github.com/scaleway/scaleway-sdk-go/internal/auth github.com/scaleway/scaleway-sdk-go/internal/errors +github.com/scaleway/scaleway-sdk-go/internal/marshaler +github.com/scaleway/scaleway-sdk-go/internal/parameter github.com/scaleway/scaleway-sdk-go/logger +github.com/scaleway/scaleway-sdk-go/namegenerator github.com/scaleway/scaleway-sdk-go/scw github.com/scaleway/scaleway-sdk-go/validation # github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529