package civogo import ( "fmt" "math/rand" "strconv" "strings" "time" ) // FakeClient is a temporary storage structure for use when you don't want to communicate with a real Civo API server type FakeClient struct { LastID int64 Charges []Charge Domains []DNSDomain DomainRecords []DNSRecord Firewalls []Firewall FirewallRules []FirewallRule InstanceSizes []InstanceSize Instances []Instance Clusters []KubernetesCluster IP []IP Networks []Network Volumes []Volume SSHKeys []SSHKey Webhooks []Webhook DiskImage []DiskImage Quota Quota Organisation Organisation OrganisationAccounts []Account OrganisationRoles []Role OrganisationTeams []Team OrganisationTeamMembers map[string][]TeamMember LoadBalancers []LoadBalancer Pools []KubernetesPool // Snapshots []Snapshot // Templates []Template } // Clienter is the interface the real civogo.Client and civogo.FakeClient implement type Clienter interface { // Charges ListCharges(from, to time.Time) ([]Charge, error) // DNS ListDNSDomains() ([]DNSDomain, error) FindDNSDomain(search string) (*DNSDomain, error) CreateDNSDomain(name string) (*DNSDomain, error) GetDNSDomain(name string) (*DNSDomain, error) UpdateDNSDomain(d *DNSDomain, name string) (*DNSDomain, error) DeleteDNSDomain(d *DNSDomain) (*SimpleResponse, error) CreateDNSRecord(domainID string, r *DNSRecordConfig) (*DNSRecord, error) ListDNSRecords(dnsDomainID string) ([]DNSRecord, error) GetDNSRecord(domainID, domainRecordID string) (*DNSRecord, error) UpdateDNSRecord(r *DNSRecord, rc *DNSRecordConfig) (*DNSRecord, error) DeleteDNSRecord(r *DNSRecord) (*SimpleResponse, error) // Firewalls ListFirewalls() ([]Firewall, error) FindFirewall(search string) (*Firewall, error) NewFirewall(*FirewallConfig) (*FirewallResult, error) RenameFirewall(id string, f *FirewallConfig) (*SimpleResponse, error) DeleteFirewall(id string) (*SimpleResponse, error) NewFirewallRule(r *FirewallRuleConfig) (*FirewallRule, error) ListFirewallRules(id string) ([]FirewallRule, error) FindFirewallRule(firewallID string, search string) (*FirewallRule, error) DeleteFirewallRule(id string, ruleID string) (*SimpleResponse, error) // Instances ListInstances(page int, perPage int) (*PaginatedInstanceList, error) ListAllInstances() ([]Instance, error) FindInstance(search string) (*Instance, error) GetInstance(id string) (*Instance, error) NewInstanceConfig() (*InstanceConfig, error) CreateInstance(config *InstanceConfig) (*Instance, error) SetInstanceTags(i *Instance, tags string) (*SimpleResponse, error) UpdateInstance(i *Instance) (*SimpleResponse, error) DeleteInstance(id string) (*SimpleResponse, error) RebootInstance(id string) (*SimpleResponse, error) HardRebootInstance(id string) (*SimpleResponse, error) SoftRebootInstance(id string) (*SimpleResponse, error) StopInstance(id string) (*SimpleResponse, error) StartInstance(id string) (*SimpleResponse, error) GetInstanceConsoleURL(id string) (string, error) UpgradeInstance(id, newSize string) (*SimpleResponse, error) MovePublicIPToInstance(id, ipAddress string) (*SimpleResponse, error) SetInstanceFirewall(id, firewallID string) (*SimpleResponse, error) // Instance sizes ListInstanceSizes() ([]InstanceSize, error) FindInstanceSizes(search string) (*InstanceSize, error) // Clusters ListKubernetesClusters() (*PaginatedKubernetesClusters, error) FindKubernetesCluster(search string) (*KubernetesCluster, error) NewKubernetesClusters(kc *KubernetesClusterConfig) (*KubernetesCluster, error) GetKubernetesCluster(id string) (*KubernetesCluster, error) UpdateKubernetesCluster(id string, i *KubernetesClusterConfig) (*KubernetesCluster, error) ListKubernetesMarketplaceApplications() ([]KubernetesMarketplaceApplication, error) DeleteKubernetesCluster(id string) (*SimpleResponse, error) RecycleKubernetesCluster(id string, hostname string) (*SimpleResponse, error) ListAvailableKubernetesVersions() ([]KubernetesVersion, error) ListKubernetesClusterInstances(id string) ([]Instance, error) FindKubernetesClusterInstance(clusterID, search string) (*Instance, error) //Pools ListKubernetesClusterPools(cid string) ([]KubernetesPool, error) GetKubernetesClusterPool(cid, pid string) (*KubernetesPool, error) FindKubernetesClusterPool(cid, search string) (*KubernetesPool, error) DeleteKubernetesClusterPoolInstance(cid, pid, id string) (*SimpleResponse, error) UpdateKubernetesClusterPool(cid, pid string, config *KubernetesClusterPoolUpdateConfig) (*KubernetesPool, error) // Networks GetDefaultNetwork() (*Network, error) NewNetwork(label string) (*NetworkResult, error) ListNetworks() ([]Network, error) FindNetwork(search string) (*Network, error) RenameNetwork(label, id string) (*NetworkResult, error) DeleteNetwork(id string) (*SimpleResponse, error) // Quota GetQuota() (*Quota, error) // Regions ListRegions() ([]Region, error) // Snapshots // CreateSnapshot(name string, r *SnapshotConfig) (*Snapshot, error) // ListSnapshots() ([]Snapshot, error) // FindSnapshot(search string) (*Snapshot, error) // DeleteSnapshot(name string) (*SimpleResponse, error) // SSHKeys ListSSHKeys() ([]SSHKey, error) NewSSHKey(name string, publicKey string) (*SimpleResponse, error) UpdateSSHKey(name string, sshKeyID string) (*SSHKey, error) FindSSHKey(search string) (*SSHKey, error) DeleteSSHKey(id string) (*SimpleResponse, error) // Templates // ListTemplates() ([]Template, error) // NewTemplate(conf *Template) (*SimpleResponse, error) // UpdateTemplate(id string, conf *Template) (*Template, error) // GetTemplateByCode(code string) (*Template, error) // FindTemplate(search string) (*Template, error) // DeleteTemplate(id string) (*SimpleResponse, error) // DiskImages ListDiskImages() ([]DiskImage, error) GetDiskImage(id string) (*DiskImage, error) FindDiskImage(search string) (*DiskImage, error) // Volumes ListVolumes() ([]Volume, error) GetVolume(id string) (*Volume, error) FindVolume(search string) (*Volume, error) NewVolume(v *VolumeConfig) (*VolumeResult, error) ResizeVolume(id string, size int) (*SimpleResponse, error) AttachVolume(id string, instance string) (*SimpleResponse, error) DetachVolume(id string) (*SimpleResponse, error) DeleteVolume(id string) (*SimpleResponse, error) // Webhooks CreateWebhook(r *WebhookConfig) (*Webhook, error) ListWebhooks() ([]Webhook, error) FindWebhook(search string) (*Webhook, error) UpdateWebhook(id string, r *WebhookConfig) (*Webhook, error) DeleteWebhook(id string) (*SimpleResponse, error) // Reserved IPs ListIPs() (*PaginatedIPs, error) FindIP(search string) (*IP, error) GetIP(id string) (*IP, error) NewIP(v *CreateIPRequest) (*IP, error) UpdateIP(id string, v *UpdateIPRequest) (*IP, error) DeleteIP(id string) (*SimpleResponse, error) AssignIP(id, resourceID, resourceType, region string) (*SimpleResponse, error) UnassignIP(id, region string) (*SimpleResponse, error) // LoadBalancer ListLoadBalancers() ([]LoadBalancer, error) GetLoadBalancer(id string) (*LoadBalancer, error) FindLoadBalancer(search string) (*LoadBalancer, error) CreateLoadBalancer(r *LoadBalancerConfig) (*LoadBalancer, error) UpdateLoadBalancer(id string, r *LoadBalancerUpdateConfig) (*LoadBalancer, error) DeleteLoadBalancer(id string) (*SimpleResponse, error) } // NewFakeClient initializes a Client that doesn't attach to a func NewFakeClient() (*FakeClient, error) { return &FakeClient{ Quota: Quota{ CPUCoreLimit: 10, InstanceCountLimit: 10, RAMMegabytesLimit: 100, DiskGigabytesLimit: 100, DiskVolumeCountLimit: 10, DiskSnapshotCountLimit: 10, PublicIPAddressLimit: 10, NetworkCountLimit: 10, SecurityGroupLimit: 10, SecurityGroupRuleLimit: 10, }, InstanceSizes: []InstanceSize{ { ID: "g3.xsmall", Name: "Extra small", CPUCores: 1, RAMMegabytes: 1024, DiskGigabytes: 10, }, { ID: "g3.small", Name: "Small", CPUCores: 2, RAMMegabytes: 2048, DiskGigabytes: 20, }, { ID: "g3.medium", Name: "Medium", CPUCores: 4, RAMMegabytes: 4096, DiskGigabytes: 40, }, }, DiskImage: []DiskImage{ { ID: "b82168fe-66f6-4b38-a3b8-5283542d5475", Name: "centos-7", Version: "7", State: "available", Distribution: "centos", Description: "", Label: "", }, { ID: "b82168fe-66f6-4b38-a3b8-52835425895", Name: "debian-9", Version: "9", State: "available", Distribution: "debian", Description: "", Label: "", }, { ID: "b82168fe-66f6-4b38-a3b8-52835428965", Name: "debian-10", Version: "10", State: "available", Distribution: "debian", Description: "", Label: "", }, { ID: "b82168fe-66f6-4b38-a3b8-528354282548", Name: "ubuntu-20-4", Version: "20.4", State: "available", Distribution: "ubuntu", Description: "", Label: "", }, }, }, nil } func (c *FakeClient) generateID() string { c.LastID++ return strconv.FormatInt(c.LastID, 10) } func (c *FakeClient) generatePublicIP() string { s := rand.NewSource(time.Now().UnixNano()) r := rand.New(s) return fmt.Sprintf("%v.%v.%v.%v", r.Intn(256), r.Intn(256), r.Intn(256), r.Intn(256)) } // ListCharges implemented in a fake way for automated tests func (c *FakeClient) ListCharges(from, to time.Time) ([]Charge, error) { return []Charge{}, nil } // ListDNSDomains implemented in a fake way for automated tests func (c *FakeClient) ListDNSDomains() ([]DNSDomain, error) { return c.Domains, nil } // FindDNSDomain implemented in a fake way for automated tests func (c *FakeClient) FindDNSDomain(search string) (*DNSDomain, error) { for _, domain := range c.Domains { if strings.Contains(domain.Name, search) { return &domain, nil } } err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // CreateDNSDomain implemented in a fake way for automated tests func (c *FakeClient) CreateDNSDomain(name string) (*DNSDomain, error) { domain := DNSDomain{ ID: c.generateID(), Name: name, } c.Domains = append(c.Domains, domain) return &domain, nil } // GetDNSDomain implemented in a fake way for automated tests func (c *FakeClient) GetDNSDomain(name string) (*DNSDomain, error) { for _, domain := range c.Domains { if domain.Name == name { return &domain, nil } } return nil, ErrDNSDomainNotFound } // UpdateDNSDomain implemented in a fake way for automated tests func (c *FakeClient) UpdateDNSDomain(d *DNSDomain, name string) (*DNSDomain, error) { for i, domain := range c.Domains { if domain.Name == d.Name { c.Domains[i] = *d return d, nil } } return nil, ErrDNSDomainNotFound } // DeleteDNSDomain implemented in a fake way for automated tests func (c *FakeClient) DeleteDNSDomain(d *DNSDomain) (*SimpleResponse, error) { for i, domain := range c.Domains { if domain.Name == d.Name { c.Domains[len(c.Domains)-1], c.Domains[i] = c.Domains[i], c.Domains[len(c.Domains)-1] c.Domains = c.Domains[:len(c.Domains)-1] return &SimpleResponse{Result: "success"}, nil } } return nil, ErrDNSDomainNotFound } // CreateDNSRecord implemented in a fake way for automated tests func (c *FakeClient) CreateDNSRecord(domainID string, r *DNSRecordConfig) (*DNSRecord, error) { record := DNSRecord{ ID: c.generateID(), DNSDomainID: domainID, Name: r.Name, Value: r.Value, Type: r.Type, } c.DomainRecords = append(c.DomainRecords, record) return &record, nil } // ListDNSRecords implemented in a fake way for automated tests func (c *FakeClient) ListDNSRecords(dnsDomainID string) ([]DNSRecord, error) { return c.DomainRecords, nil } // GetDNSRecord implemented in a fake way for automated tests func (c *FakeClient) GetDNSRecord(domainID, domainRecordID string) (*DNSRecord, error) { for _, record := range c.DomainRecords { if record.ID == domainRecordID && record.DNSDomainID == domainID { return &record, nil } } return nil, ErrDNSRecordNotFound } // UpdateDNSRecord implemented in a fake way for automated tests func (c *FakeClient) UpdateDNSRecord(r *DNSRecord, rc *DNSRecordConfig) (*DNSRecord, error) { for i, record := range c.DomainRecords { if record.ID == r.ID { record := DNSRecord{ ID: c.generateID(), DNSDomainID: record.DNSDomainID, Name: rc.Name, Value: rc.Value, Type: rc.Type, } c.DomainRecords[i] = record return &record, nil } } return nil, ErrDNSRecordNotFound } // DeleteDNSRecord implemented in a fake way for automated tests func (c *FakeClient) DeleteDNSRecord(r *DNSRecord) (*SimpleResponse, error) { for i, record := range c.DomainRecords { if record.ID == r.ID { c.DomainRecords[len(c.DomainRecords)-1], c.DomainRecords[i] = c.DomainRecords[i], c.DomainRecords[len(c.DomainRecords)-1] c.DomainRecords = c.DomainRecords[:len(c.DomainRecords)-1] return &SimpleResponse{Result: "success"}, nil } } return nil, ErrDNSRecordNotFound } // ListFirewalls implemented in a fake way for automated tests func (c *FakeClient) ListFirewalls() ([]Firewall, error) { return c.Firewalls, nil } // FindFirewall implemented in a fake way for automated tests func (c *FakeClient) FindFirewall(search string) (*Firewall, error) { for _, firewall := range c.Firewalls { if strings.Contains(firewall.Name, search) { return &firewall, nil } } err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // NewFirewall implemented in a fake way for automated tests func (c *FakeClient) NewFirewall(*FirewallConfig) (*FirewallResult, error) { firewall := Firewall{ ID: c.generateID(), Name: "fw-name", } c.Firewalls = append(c.Firewalls, firewall) return &FirewallResult{ ID: firewall.ID, Name: firewall.Name, Result: "success", }, nil } // RenameFirewall implemented in a fake way for automated tests func (c *FakeClient) RenameFirewall(id string, f *FirewallConfig) (*SimpleResponse, error) { for i, firewall := range c.Firewalls { if firewall.ID == id { c.Firewalls[i].Name = f.Name return &SimpleResponse{Result: "success"}, nil } } err := fmt.Errorf("unable to find %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // DeleteFirewall implemented in a fake way for automated tests func (c *FakeClient) DeleteFirewall(id string) (*SimpleResponse, error) { for i, firewall := range c.Firewalls { if firewall.ID == id { c.Firewalls[len(c.Firewalls)-1], c.Firewalls[i] = c.Firewalls[i], c.Firewalls[len(c.Firewalls)-1] c.Firewalls = c.Firewalls[:len(c.Firewalls)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // NewFirewallRule implemented in a fake way for automated tests func (c *FakeClient) NewFirewallRule(r *FirewallRuleConfig) (*FirewallRule, error) { rule := FirewallRule{ ID: c.generateID(), Protocol: r.Protocol, StartPort: r.StartPort, EndPort: r.EndPort, Cidr: r.Cidr, Label: r.Label, } c.FirewallRules = append(c.FirewallRules, rule) return &rule, nil } // ListFirewallRules implemented in a fake way for automated tests func (c *FakeClient) ListFirewallRules(id string) ([]FirewallRule, error) { return c.FirewallRules, nil } // FindFirewallRule implemented in a fake way for automated tests func (c *FakeClient) FindFirewallRule(firewallID string, search string) (*FirewallRule, error) { for _, rule := range c.FirewallRules { if rule.FirewallID == firewallID && strings.Contains(rule.Label, search) { return &rule, nil } } err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // DeleteFirewallRule implemented in a fake way for automated tests func (c *FakeClient) DeleteFirewallRule(id string, ruleID string) (*SimpleResponse, error) { for i, rule := range c.FirewallRules { if rule.ID == ruleID { c.FirewallRules[len(c.FirewallRules)-1], c.FirewallRules[i] = c.FirewallRules[i], c.FirewallRules[len(c.FirewallRules)-1] c.FirewallRules = c.FirewallRules[:len(c.FirewallRules)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // ListInstances implemented in a fake way for automated tests func (c *FakeClient) ListInstances(page int, perPage int) (*PaginatedInstanceList, error) { return &PaginatedInstanceList{ Items: c.Instances, Page: page, PerPage: perPage, Pages: page, }, nil } // ListAllInstances implemented in a fake way for automated tests func (c *FakeClient) ListAllInstances() ([]Instance, error) { return c.Instances, nil } // FindInstance implemented in a fake way for automated tests func (c *FakeClient) FindInstance(search string) (*Instance, error) { for _, instance := range c.Instances { if strings.Contains(instance.Hostname, search) { return &instance, nil } } err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // GetInstance implemented in a fake way for automated tests func (c *FakeClient) GetInstance(id string) (*Instance, error) { for _, instance := range c.Instances { if instance.ID == id { return &instance, nil } } err := fmt.Errorf("unable to find %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // NewInstanceConfig implemented in a fake way for automated tests func (c *FakeClient) NewInstanceConfig() (*InstanceConfig, error) { return &InstanceConfig{}, nil } // CreateInstance implemented in a fake way for automated tests func (c *FakeClient) CreateInstance(config *InstanceConfig) (*Instance, error) { instance := Instance{ ID: c.generateID(), Hostname: config.Hostname, Size: config.Size, Region: config.Region, TemplateID: config.TemplateID, InitialUser: config.InitialUser, SSHKey: config.SSHKeyID, Tags: config.Tags, PublicIP: c.generatePublicIP(), } c.Instances = append(c.Instances, instance) return &instance, nil } // SetInstanceTags implemented in a fake way for automated tests func (c *FakeClient) SetInstanceTags(i *Instance, tags string) (*SimpleResponse, error) { for idx, instance := range c.Instances { if instance.ID == i.ID { c.Instances[idx].Tags = strings.Split(tags, " ") return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // UpdateInstance implemented in a fake way for automated tests func (c *FakeClient) UpdateInstance(i *Instance) (*SimpleResponse, error) { for idx, instance := range c.Instances { if instance.ID == i.ID { c.Instances[idx] = *i return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // DeleteInstance implemented in a fake way for automated tests func (c *FakeClient) DeleteInstance(id string) (*SimpleResponse, error) { for i, instance := range c.Instances { if instance.ID == id { c.Instances[len(c.Instances)-1], c.Instances[i] = c.Instances[i], c.Instances[len(c.Instances)-1] c.Instances = c.Instances[:len(c.Instances)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // RebootInstance implemented in a fake way for automated tests func (c *FakeClient) RebootInstance(id string) (*SimpleResponse, error) { return &SimpleResponse{Result: "success"}, nil } // HardRebootInstance implemented in a fake way for automated tests func (c *FakeClient) HardRebootInstance(id string) (*SimpleResponse, error) { return &SimpleResponse{Result: "success"}, nil } // SoftRebootInstance implemented in a fake way for automated tests func (c *FakeClient) SoftRebootInstance(id string) (*SimpleResponse, error) { return &SimpleResponse{Result: "success"}, nil } // StopInstance implemented in a fake way for automated tests func (c *FakeClient) StopInstance(id string) (*SimpleResponse, error) { return &SimpleResponse{Result: "success"}, nil } // StartInstance implemented in a fake way for automated tests func (c *FakeClient) StartInstance(id string) (*SimpleResponse, error) { return &SimpleResponse{Result: "success"}, nil } // GetInstanceConsoleURL implemented in a fake way for automated tests func (c *FakeClient) GetInstanceConsoleURL(id string) (string, error) { return fmt.Sprintf("https://console.example.com/%s", id), nil } // UpgradeInstance implemented in a fake way for automated tests func (c *FakeClient) UpgradeInstance(id, newSize string) (*SimpleResponse, error) { for idx, instance := range c.Instances { if instance.ID == id { c.Instances[idx].Size = newSize return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // MovePublicIPToInstance implemented in a fake way for automated tests func (c *FakeClient) MovePublicIPToInstance(id, ipAddress string) (*SimpleResponse, error) { oldIndex := -1 for idx, instance := range c.Instances { if instance.PublicIP == ipAddress { oldIndex = idx } } newIndex := -1 for idx, instance := range c.Instances { if instance.ID == id { newIndex = idx } } if oldIndex == -1 || newIndex == -1 { return &SimpleResponse{Result: "failed"}, nil } c.Instances[newIndex].PublicIP = c.Instances[oldIndex].PublicIP c.Instances[oldIndex].PublicIP = "" return &SimpleResponse{Result: "success"}, nil } // SetInstanceFirewall implemented in a fake way for automated tests func (c *FakeClient) SetInstanceFirewall(id, firewallID string) (*SimpleResponse, error) { for idx, instance := range c.Instances { if instance.ID == id { c.Instances[idx].FirewallID = firewallID return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // ListInstanceSizes implemented in a fake way for automated tests func (c *FakeClient) ListInstanceSizes() ([]InstanceSize, error) { return c.InstanceSizes, nil } // FindInstanceSizes implemented in a fake way for automated tests func (c *FakeClient) FindInstanceSizes(search string) (*InstanceSize, error) { for _, size := range c.InstanceSizes { if strings.Contains(size.Name, search) || size.ID == search { return &size, nil } } err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // ListKubernetesClusters implemented in a fake way for automated tests func (c *FakeClient) ListKubernetesClusters() (*PaginatedKubernetesClusters, error) { return &PaginatedKubernetesClusters{ Items: c.Clusters, Page: 1, PerPage: 10, Pages: 1, }, nil } // FindKubernetesCluster implemented in a fake way for automated tests func (c *FakeClient) FindKubernetesCluster(search string) (*KubernetesCluster, error) { for _, cluster := range c.Clusters { if strings.Contains(cluster.Name, search) || cluster.ID == search { return &cluster, nil } } err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // ListKubernetesClusterInstances implemented in a fake way for automated tests func (c *FakeClient) ListKubernetesClusterInstances(id string) ([]Instance, error) { for _, cluster := range c.Clusters { if cluster.ID == id { instaces := make([]Instance, 0) for _, kins := range cluster.Instances { for _, instance := range c.Instances { if instance.ID == kins.ID { instaces = append(instaces, instance) } } } return instaces, nil } } err := fmt.Errorf("unable to find %s, zero matches", id) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } // FindKubernetesClusterInstance implemented in a fake way for automated tests func (c *FakeClient) FindKubernetesClusterInstance(clusterID, search string) (*Instance, error) { instances, err := c.ListKubernetesClusterInstances(clusterID) if err != nil { return nil, decodeError(err) } exactMatch := false partialMatchesCount := 0 result := Instance{} for _, instance := range instances { if instance.Hostname == search || instance.ID == search { exactMatch = true result = instance } else if strings.Contains(instance.Hostname, search) || strings.Contains(instance.ID, search) { if !exactMatch { result = instance partialMatchesCount++ } } } if exactMatch || partialMatchesCount == 1 { return &result, nil } else if partialMatchesCount > 1 { err := fmt.Errorf("unable to find %s because there were multiple matches", search) return nil, MultipleMatchesError.wrap(err) } else { err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } } // NewKubernetesClusters implemented in a fake way for automated tests func (c *FakeClient) NewKubernetesClusters(kc *KubernetesClusterConfig) (*KubernetesCluster, error) { cluster := KubernetesCluster{ ID: c.generateID(), Name: kc.Name, MasterIP: c.generatePublicIP(), NumTargetNode: kc.NumTargetNodes, TargetNodeSize: kc.TargetNodesSize, Ready: true, Status: "ACTIVE", Instances: make([]KubernetesInstance, 0), Pools: make([]KubernetesPool, 0), } pool := KubernetesPool{ Instances: make([]KubernetesInstance, 0), } for i := 0; i < kc.NumTargetNodes; i++ { instance := KubernetesInstance{ ID: c.generateID(), Hostname: fmt.Sprintf("%s_pool_%d", kc.Name, i), } pool.Instances = append(pool.Instances, instance) cluster.Instances = append(pool.Instances, instance) } cluster.Pools = append(cluster.Pools, pool) c.Clusters = append(c.Clusters, cluster) return &cluster, nil } // GetKubernetesCluster implemented in a fake way for automated tests func (c *FakeClient) GetKubernetesCluster(id string) (*KubernetesCluster, error) { for _, cluster := range c.Clusters { if cluster.ID == id { return &cluster, nil } } err := fmt.Errorf("unable to find %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // UpdateKubernetesCluster implemented in a fake way for automated tests func (c *FakeClient) UpdateKubernetesCluster(id string, kc *KubernetesClusterConfig) (*KubernetesCluster, error) { for i, cluster := range c.Clusters { if cluster.ID == id { c.Clusters[i].Name = kc.Name c.Clusters[i].NumTargetNode = kc.NumTargetNodes c.Clusters[i].TargetNodeSize = kc.TargetNodesSize return &cluster, nil } } err := fmt.Errorf("unable to find %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // ListKubernetesMarketplaceApplications implemented in a fake way for automated tests func (c *FakeClient) ListKubernetesMarketplaceApplications() ([]KubernetesMarketplaceApplication, error) { return []KubernetesMarketplaceApplication{}, nil } // DeleteKubernetesCluster implemented in a fake way for automated tests func (c *FakeClient) DeleteKubernetesCluster(id string) (*SimpleResponse, error) { for i, cluster := range c.Clusters { if cluster.ID == id { c.Clusters[len(c.Clusters)-1], c.Clusters[i] = c.Clusters[i], c.Clusters[len(c.Clusters)-1] c.Clusters = c.Clusters[:len(c.Clusters)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // RecycleKubernetesCluster implemented in a fake way for automated tests func (c *FakeClient) RecycleKubernetesCluster(id string, hostname string) (*SimpleResponse, error) { return &SimpleResponse{Result: "success"}, nil } // ListAvailableKubernetesVersions implemented in a fake way for automated tests func (c *FakeClient) ListAvailableKubernetesVersions() ([]KubernetesVersion, error) { return []KubernetesVersion{ { Version: "1.20+k3s1", Type: "stable", }, }, nil } // GetDefaultNetwork implemented in a fake way for automated tests func (c *FakeClient) GetDefaultNetwork() (*Network, error) { for _, network := range c.Networks { if network.Default { return &network, nil } } err := fmt.Errorf("unable to find default network, zero matches") return nil, ZeroMatchesError.wrap(err) } // NewNetwork implemented in a fake way for automated tests func (c *FakeClient) NewNetwork(label string) (*NetworkResult, error) { network := Network{ ID: c.generateID(), Name: label, } c.Networks = append(c.Networks, network) return &NetworkResult{ ID: network.ID, Label: network.Name, Result: "success", }, nil } // ListNetworks implemented in a fake way for automated tests func (c *FakeClient) ListNetworks() ([]Network, error) { return c.Networks, nil } // FindNetwork implemented in a fake way for automated tests func (c *FakeClient) FindNetwork(search string) (*Network, error) { for _, network := range c.Networks { if strings.Contains(network.Name, search) { return &network, nil } } err := fmt.Errorf("unable to find default network, zero matches") return nil, ZeroMatchesError.wrap(err) } // RenameNetwork implemented in a fake way for automated tests func (c *FakeClient) RenameNetwork(label, id string) (*NetworkResult, error) { for i, network := range c.Networks { if network.ID == id { c.Networks[i].Label = label return &NetworkResult{ ID: network.ID, Label: network.Label, Result: "success", }, nil } } err := fmt.Errorf("unable to find default network, zero matches") return nil, ZeroMatchesError.wrap(err) } // DeleteNetwork implemented in a fake way for automated tests func (c *FakeClient) DeleteNetwork(id string) (*SimpleResponse, error) { for i, network := range c.Networks { if network.ID == id { c.Networks[len(c.Networks)-1], c.Networks[i] = c.Networks[i], c.Networks[len(c.Networks)-1] c.Networks = c.Networks[:len(c.Networks)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // GetQuota implemented in a fake way for automated tests func (c *FakeClient) GetQuota() (*Quota, error) { return &c.Quota, nil } // ListRegions implemented in a fake way for automated tests func (c *FakeClient) ListRegions() ([]Region, error) { return []Region{ { Code: "FAKE1", Name: "Fake testing region", Default: true, }, }, nil } // CreateSnapshot implemented in a fake way for automated tests // func (c *FakeClient) CreateSnapshot(name string, r *SnapshotConfig) (*Snapshot, error) { // snapshot := Snapshot{ // ID: c.generateID(), // Name: name, // InstanceID: r.InstanceID, // Cron: r.Cron, // } // c.Snapshots = append(c.Snapshots, snapshot) // return &snapshot, nil // } // ListSnapshots implemented in a fake way for automated tests // func (c *FakeClient) ListSnapshots() ([]Snapshot, error) { // return c.Snapshots, nil // } // FindSnapshot implemented in a fake way for automated tests // func (c *FakeClient) FindSnapshot(search string) (*Snapshot, error) { // for _, snapshot := range c.Snapshots { // if strings.Contains(snapshot.Name, search) { // return &snapshot, nil // } // } // err := fmt.Errorf("unable to find %s, zero matches", search) // return nil, ZeroMatchesError.wrap(err) // } // DeleteSnapshot implemented in a fake way for automated tests // func (c *FakeClient) DeleteSnapshot(name string) (*SimpleResponse, error) { // for i, snapshot := range c.Snapshots { // if snapshot.Name == name { // c.Snapshots[len(c.Snapshots)-1], c.Snapshots[i] = c.Snapshots[i], c.Snapshots[len(c.Snapshots)-1] // c.Snapshots = c.Snapshots[:len(c.Snapshots)-1] // return &SimpleResponse{Result: "success"}, nil // } // } // return &SimpleResponse{Result: "failed"}, nil // } // ListSSHKeys implemented in a fake way for automated tests func (c *FakeClient) ListSSHKeys() ([]SSHKey, error) { return c.SSHKeys, nil } // NewSSHKey implemented in a fake way for automated tests func (c *FakeClient) NewSSHKey(name string, publicKey string) (*SimpleResponse, error) { sshKey := SSHKey{ Name: name, Fingerprint: publicKey, // This is weird, but we're just storing a value } c.SSHKeys = append(c.SSHKeys, sshKey) return &SimpleResponse{Result: "success"}, nil } // UpdateSSHKey implemented in a fake way for automated tests func (c *FakeClient) UpdateSSHKey(name string, sshKeyID string) (*SSHKey, error) { for i, sshKey := range c.SSHKeys { if sshKey.ID == sshKeyID { c.SSHKeys[i].Name = name return &sshKey, nil } } err := fmt.Errorf("unable to find SSH key %s, zero matches", sshKeyID) return nil, ZeroMatchesError.wrap(err) } // FindSSHKey implemented in a fake way for automated tests func (c *FakeClient) FindSSHKey(search string) (*SSHKey, error) { for _, sshKey := range c.SSHKeys { if strings.Contains(sshKey.Name, search) { return &sshKey, nil } } err := fmt.Errorf("unable to find SSH key %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // DeleteSSHKey implemented in a fake way for automated tests func (c *FakeClient) DeleteSSHKey(id string) (*SimpleResponse, error) { for i, sshKey := range c.SSHKeys { if sshKey.ID == id { c.SSHKeys[len(c.SSHKeys)-1], c.SSHKeys[i] = c.SSHKeys[i], c.SSHKeys[len(c.SSHKeys)-1] c.SSHKeys = c.SSHKeys[:len(c.SSHKeys)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // ListTemplates implemented in a fake way for automated tests // func (c *FakeClient) ListTemplates() ([]Template, error) { // return c.Templates, nil // } // NewTemplate implemented in a fake way for automated tests // func (c *FakeClient) NewTemplate(conf *Template) (*SimpleResponse, error) { // template := Template{ // ID: conf.ID, // Name: conf.Name, // CloudConfig: conf.CloudConfig, // ImageID: conf.ImageID, // } // c.Templates = append(c.Templates, template) // return &SimpleResponse{Result: "success"}, nil // } // UpdateTemplate implemented in a fake way for automated tests // func (c *FakeClient) UpdateTemplate(id string, conf *Template) (*Template, error) { // for i, template := range c.Templates { // if template.ID == id { // c.Templates[i].Name = conf.Name // c.Templates[i].CloudConfig = conf.CloudConfig // c.Templates[i].ImageID = conf.ImageID // return &template, nil // } // } // err := fmt.Errorf("unable to find SSH key %s, zero matches", id) // return nil, ZeroMatchesError.wrap(err) // } // GetTemplateByCode implemented in a fake way for automated tests // func (c *FakeClient) GetTemplateByCode(code string) (*Template, error) { // for _, template := range c.Templates { // if template.Code == code { // return &template, nil // } // } // err := fmt.Errorf("unable to find SSH key %s, zero matches", code) // return nil, ZeroMatchesError.wrap(err) // } // FindTemplate implemented in a fake way for automated tests // func (c *FakeClient) FindTemplate(search string) (*Template, error) { // for _, template := range c.Templates { // if strings.Contains(template.Name, search) { // return &template, nil // } // } // err := fmt.Errorf("unable to find template %s, zero matches", search) // return nil, ZeroMatchesError.wrap(err) // } // DeleteTemplate implemented in a fake way for automated tests // func (c *FakeClient) DeleteTemplate(id string) (*SimpleResponse, error) { // for i, template := range c.Templates { // if template.ID == id { // c.Templates[len(c.Templates)-1], c.Templates[i] = c.Templates[i], c.Templates[len(c.Templates)-1] // c.Templates = c.Templates[:len(c.Templates)-1] // return &SimpleResponse{Result: "success"}, nil // } // } // return &SimpleResponse{Result: "failed"}, nil // } // ListDiskImages implemented in a fake way for automated tests func (c *FakeClient) ListDiskImages() ([]DiskImage, error) { return c.DiskImage, nil } // GetDiskImage implemented in a fake way for automated tests func (c *FakeClient) GetDiskImage(id string) (*DiskImage, error) { for k, v := range c.DiskImage { if v.ID == id { return &c.DiskImage[k], nil } } err := fmt.Errorf("unable to find disk image %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // FindDiskImage implemented in a fake way for automated tests func (c *FakeClient) FindDiskImage(search string) (*DiskImage, error) { for _, diskimage := range c.DiskImage { if strings.Contains(diskimage.Name, search) || strings.Contains(diskimage.ID, search) { return &diskimage, nil } } err := fmt.Errorf("unable to find volume %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // ListVolumes implemented in a fake way for automated tests func (c *FakeClient) ListVolumes() ([]Volume, error) { return c.Volumes, nil } // GetVolume implemented in a fake way for automated tests func (c *FakeClient) GetVolume(id string) (*Volume, error) { for _, volume := range c.Volumes { if volume.ID == id { return &volume, nil } } err := fmt.Errorf("unable to get volume %s", id) return nil, ZeroMatchesError.wrap(err) } // FindVolume implemented in a fake way for automated tests func (c *FakeClient) FindVolume(search string) (*Volume, error) { for _, volume := range c.Volumes { if strings.Contains(volume.Name, search) || strings.Contains(volume.ID, search) { return &volume, nil } } err := fmt.Errorf("unable to find volume %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // NewVolume implemented in a fake way for automated tests func (c *FakeClient) NewVolume(v *VolumeConfig) (*VolumeResult, error) { volume := Volume{ ID: c.generateID(), Name: v.Name, SizeGigabytes: v.SizeGigabytes, Status: "available", } c.Volumes = append(c.Volumes, volume) return &VolumeResult{ ID: volume.ID, Name: volume.Name, Result: "success", }, nil } // ResizeVolume implemented in a fake way for automated tests func (c *FakeClient) ResizeVolume(id string, size int) (*SimpleResponse, error) { for i, volume := range c.Volumes { if volume.ID == id { c.Volumes[i].SizeGigabytes = size return &SimpleResponse{Result: "success"}, nil } } err := fmt.Errorf("unable to find volume %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // AttachVolume implemented in a fake way for automated tests func (c *FakeClient) AttachVolume(id string, instance string) (*SimpleResponse, error) { for i, volume := range c.Volumes { if volume.ID == id { c.Volumes[i].InstanceID = instance c.Volumes[i].Status = "attached" return &SimpleResponse{Result: "success"}, nil } } err := fmt.Errorf("unable to find volume %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // DetachVolume implemented in a fake way for automated tests func (c *FakeClient) DetachVolume(id string) (*SimpleResponse, error) { for i, volume := range c.Volumes { if volume.ID == id { c.Volumes[i].InstanceID = "" c.Volumes[i].Status = "available" return &SimpleResponse{Result: "success"}, nil } } err := fmt.Errorf("unable to find volume %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // DeleteVolume implemented in a fake way for automated tests func (c *FakeClient) DeleteVolume(id string) (*SimpleResponse, error) { for i, volume := range c.Volumes { if volume.ID == id { c.Volumes[len(c.Volumes)-1], c.Volumes[i] = c.Volumes[i], c.Volumes[len(c.Volumes)-1] c.Volumes = c.Volumes[:len(c.Volumes)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // CreateWebhook implemented in a fake way for automated tests func (c *FakeClient) CreateWebhook(r *WebhookConfig) (*Webhook, error) { webhook := Webhook{ ID: c.generateID(), Events: r.Events, Secret: r.Secret, URL: r.URL, } c.Webhooks = append(c.Webhooks, webhook) return &webhook, nil } // ListWebhooks implemented in a fake way for automated tests func (c *FakeClient) ListWebhooks() ([]Webhook, error) { return c.Webhooks, nil } // FindWebhook implemented in a fake way for automated tests func (c *FakeClient) FindWebhook(search string) (*Webhook, error) { for _, webhook := range c.Webhooks { if strings.Contains(webhook.Secret, search) || strings.Contains(webhook.URL, search) { return &webhook, nil } } err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } // UpdateWebhook implemented in a fake way for automated tests func (c *FakeClient) UpdateWebhook(id string, r *WebhookConfig) (*Webhook, error) { for i, webhook := range c.Webhooks { if webhook.ID == id { c.Webhooks[i].Events = r.Events c.Webhooks[i].Secret = r.Secret c.Webhooks[i].URL = r.URL return &webhook, nil } } err := fmt.Errorf("unable to find %s, zero matches", id) return nil, ZeroMatchesError.wrap(err) } // DeleteWebhook implemented in a fake way for automated tests func (c *FakeClient) DeleteWebhook(id string) (*SimpleResponse, error) { for i, webhook := range c.Webhooks { if webhook.ID == id { c.Webhooks[len(c.Webhooks)-1], c.Webhooks[i] = c.Webhooks[i], c.Webhooks[len(c.Webhooks)-1] c.Webhooks = c.Webhooks[:len(c.Webhooks)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // ListPermissions implemented in a fake way for automated tests func (c *FakeClient) ListPermissions() ([]Permission, error) { return []Permission{ { Name: "instance.create", Description: "Create Compute instances", }, { Name: "kubernetes.*", Description: "Manage Civo Kubernetes clusters", }, }, nil } // GetOrganisation implemented in a fake way for automated tests func (c *FakeClient) GetOrganisation() (*Organisation, error) { return &c.Organisation, nil } // CreateOrganisation implemented in a fake way for automated tests func (c *FakeClient) CreateOrganisation(name string) (*Organisation, error) { c.Organisation.ID = c.generateID() c.Organisation.Name = name return &c.Organisation, nil } // RenameOrganisation implemented in a fake way for automated tests func (c *FakeClient) RenameOrganisation(name string) (*Organisation, error) { c.Organisation.Name = name return &c.Organisation, nil } // AddAccountToOrganisation implemented in a fake way for automated tests func (c *FakeClient) AddAccountToOrganisation(accountID string) ([]Account, error) { c.OrganisationAccounts = append(c.OrganisationAccounts, Account{ ID: accountID, CreatedAt: time.Now(), UpdatedAt: time.Now(), }) return c.ListAccountsInOrganisation() } // ListAccountsInOrganisation implemented in a fake way for automated tests func (c *FakeClient) ListAccountsInOrganisation() ([]Account, error) { return c.OrganisationAccounts, nil } // ListRoles implemented in a fake way for automated tests func (c *FakeClient) ListRoles() ([]Role, error) { return c.OrganisationRoles, nil } // CreateRole implemented in a fake way for automated tests func (c *FakeClient) CreateRole(name, permissions string) (*Role, error) { role := Role{ ID: c.generateID(), Name: name, Permissions: permissions, } c.OrganisationRoles = append(c.OrganisationRoles, role) return &role, nil } // DeleteRole implemented in a fake way for automated tests func (c *FakeClient) DeleteRole(id string) (*SimpleResponse, error) { for i, role := range c.OrganisationRoles { if role.ID == id { c.OrganisationRoles[len(c.OrganisationRoles)-1], c.OrganisationRoles[i] = c.OrganisationRoles[i], c.OrganisationRoles[len(c.OrganisationRoles)-1] c.OrganisationRoles = c.OrganisationRoles[:len(c.OrganisationRoles)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, fmt.Errorf("unable to find that role") } // ListTeams implemented in a fake way for automated tests func (c *FakeClient) ListTeams() ([]Team, error) { return c.OrganisationTeams, nil } // CreateTeam implemented in a fake way for automated tests func (c *FakeClient) CreateTeam(name string) (*Team, error) { team := Team{ ID: c.generateID(), Name: name, CreatedAt: time.Time{}, UpdatedAt: time.Time{}, } c.OrganisationTeams = append(c.OrganisationTeams, team) return &team, nil } // RenameTeam implemented in a fake way for automated tests func (c *FakeClient) RenameTeam(teamID, name string) (*Team, error) { for _, team := range c.OrganisationTeams { if team.ID == teamID { team.Name = name return &team, nil } } return nil, fmt.Errorf("unable to find that role") } // DeleteTeam implemented in a fake way for automated tests func (c *FakeClient) DeleteTeam(id string) (*SimpleResponse, error) { for i, team := range c.OrganisationTeams { if team.ID == id { c.OrganisationTeams[len(c.OrganisationTeams)-1], c.OrganisationTeams[i] = c.OrganisationTeams[i], c.OrganisationTeams[len(c.OrganisationTeams)-1] c.OrganisationTeams = c.OrganisationTeams[:len(c.OrganisationTeams)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failure"}, fmt.Errorf("unable to find that team") } // ListTeamMembers implemented in a fake way for automated tests func (c *FakeClient) ListTeamMembers(teamID string) ([]TeamMember, error) { return c.OrganisationTeamMembers[teamID], nil } // AddTeamMember implemented in a fake way for automated tests func (c *FakeClient) AddTeamMember(teamID, userID, permissions, roles string) ([]TeamMember, error) { c.OrganisationTeamMembers[teamID] = append(c.OrganisationTeamMembers[teamID], TeamMember{ ID: c.generateID(), TeamID: teamID, UserID: userID, Permissions: permissions, Roles: roles, CreatedAt: time.Now(), UpdatedAt: time.Now(), }) return c.ListTeamMembers(teamID) } // UpdateTeamMember implemented in a fake way for automated tests func (c *FakeClient) UpdateTeamMember(teamID, teamMemberID, permissions, roles string) (*TeamMember, error) { for _, teamMember := range c.OrganisationTeamMembers[teamID] { if teamMember.ID == teamMemberID { teamMember.Permissions = permissions teamMember.Roles = roles return &teamMember, nil } } return nil, fmt.Errorf("unable to find that role") } // RemoveTeamMember implemented in a fake way for automated tests func (c *FakeClient) RemoveTeamMember(teamID, teamMemberID string) (*SimpleResponse, error) { for i, teamMember := range c.OrganisationTeamMembers[teamID] { if teamMember.ID == teamMemberID { c.OrganisationTeamMembers[teamID][len(c.OrganisationTeamMembers[teamID])-1], c.OrganisationTeamMembers[teamID][i] = c.OrganisationTeamMembers[teamID][i], c.OrganisationTeamMembers[teamID][len(c.OrganisationTeamMembers[teamID])-1] c.OrganisationTeamMembers[teamID] = c.OrganisationTeamMembers[teamID][:len(c.OrganisationTeamMembers[teamID])-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failure"}, fmt.Errorf("unable to find that team member") } // ListLoadBalancers implemented in a fake way for automated tests func (c *FakeClient) ListLoadBalancers() ([]LoadBalancer, error) { return c.LoadBalancers, nil } // GetLoadBalancer implemented in a fake way for automated tests func (c *FakeClient) GetLoadBalancer(id string) (*LoadBalancer, error) { for _, lb := range c.LoadBalancers { if lb.ID == id { return &lb, nil } } err := fmt.Errorf("unable to get load balancer %s", id) return nil, DatabaseLoadBalancerNotFoundError.wrap(err) } // FindLoadBalancer implemented in a fake way for automated tests func (c *FakeClient) FindLoadBalancer(search string) (*LoadBalancer, error) { exactMatch := false partialMatchesCount := 0 result := LoadBalancer{} for _, lb := range c.LoadBalancers { if lb.ID == search || lb.Name == search { exactMatch = true result = lb } else if strings.Contains(lb.Name, search) || strings.Contains(lb.ID, search) { if !exactMatch { result = lb partialMatchesCount++ } } } if exactMatch || partialMatchesCount == 1 { return &result, nil } else if partialMatchesCount > 1 { err := fmt.Errorf("unable to find %s because there were multiple matches", search) return nil, MultipleMatchesError.wrap(err) } else { err := fmt.Errorf("unable to find %s, zero matches", search) return nil, ZeroMatchesError.wrap(err) } } // CreateLoadBalancer implemented in a fake way for automated tests func (c *FakeClient) CreateLoadBalancer(r *LoadBalancerConfig) (*LoadBalancer, error) { loadbalancer := LoadBalancer{ ID: c.generateID(), Name: r.Name, Algorithm: r.Algorithm, ExternalTrafficPolicy: r.ExternalTrafficPolicy, SessionAffinityConfigTimeout: r.SessionAffinityConfigTimeout, SessionAffinity: r.SessionAffinity, EnableProxyProtocol: r.EnableProxyProtocol, FirewallID: r.FirewallID, ClusterID: r.ClusterID, } if r.Algorithm == "" { loadbalancer.Algorithm = "round_robin" } if r.FirewallID == "" { loadbalancer.FirewallID = c.generateID() } if r.ExternalTrafficPolicy == "" { loadbalancer.ExternalTrafficPolicy = "Cluster" } backends := make([]LoadBalancerBackend, 0) for _, b := range r.Backends { backend := LoadBalancerBackend{ IP: b.IP, Protocol: b.Protocol, SourcePort: b.SourcePort, TargetPort: b.TargetPort, } backends = append(backends, backend) } loadbalancer.Backends = backends loadbalancer.PublicIP = c.generatePublicIP() loadbalancer.State = "available" c.LoadBalancers = append(c.LoadBalancers, loadbalancer) return &loadbalancer, nil } // UpdateLoadBalancer implemented in a fake way for automated tests func (c *FakeClient) UpdateLoadBalancer(id string, r *LoadBalancerUpdateConfig) (*LoadBalancer, error) { for _, lb := range c.LoadBalancers { if lb.ID == id { lb.Name = r.Name lb.Algorithm = r.Algorithm lb.EnableProxyProtocol = r.EnableProxyProtocol lb.ExternalTrafficPolicy = r.ExternalTrafficPolicy lb.SessionAffinity = r.SessionAffinity lb.SessionAffinityConfigTimeout = r.SessionAffinityConfigTimeout backends := make([]LoadBalancerBackend, len(r.Backends)) for i, b := range r.Backends { backends[i].IP = b.IP backends[i].Protocol = b.Protocol backends[i].SourcePort = b.SourcePort backends[i].TargetPort = b.TargetPort } if r.ExternalTrafficPolicy == "" { lb.ExternalTrafficPolicy = "Cluster" } return &lb, nil } } err := fmt.Errorf("unable to find load balancer %s", id) return nil, DatabaseLoadBalancerNotFoundError.wrap(err) } // DeleteLoadBalancer implemented in a fake way for automated tests func (c *FakeClient) DeleteLoadBalancer(id string) (*SimpleResponse, error) { for i, lb := range c.LoadBalancers { if lb.ID == id { c.LoadBalancers[len(c.LoadBalancers)-1], c.LoadBalancers[i] = c.LoadBalancers[i], c.LoadBalancers[len(c.LoadBalancers)-1] c.LoadBalancers = c.LoadBalancers[:len(c.LoadBalancers)-1] return &SimpleResponse{Result: "success"}, nil } } return &SimpleResponse{Result: "failed"}, nil } // ListKubernetesClusterPools implemented in a fake way for automated tests func (c *FakeClient) ListKubernetesClusterPools(cid string) ([]KubernetesPool, error) { pools := []KubernetesPool{} found := false for _, cs := range c.Clusters { if cs.ID == cid { found = true pools = cs.Pools break } } if found { return pools, nil } err := fmt.Errorf("unable to get kubernetes cluster %s", cid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } // GetKubernetesClusterPool implemented in a fake way for automated tests func (c *FakeClient) GetKubernetesClusterPool(cid, pid string) (*KubernetesPool, error) { pool := &KubernetesPool{} clusterFound := false poolFound := false for _, cs := range c.Clusters { if cs.ID == cid { clusterFound = true for _, p := range cs.Pools { if p.ID == pid { poolFound = true pool = &p break } } } } if !clusterFound { err := fmt.Errorf("unable to get kubernetes cluster %s", cid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } if !poolFound { err := fmt.Errorf("unable to get kubernetes pool %s", pid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } return pool, nil } // FindKubernetesClusterPool implemented in a fake way for automated tests func (c *FakeClient) FindKubernetesClusterPool(cid, search string) (*KubernetesPool, error) { pool := &KubernetesPool{} clusterFound := false poolFound := false for _, cs := range c.Clusters { if cs.ID == cid { clusterFound = true for _, p := range cs.Pools { if p.ID == search || strings.Contains(p.ID, search) { poolFound = true pool = &p break } } } } if !clusterFound { err := fmt.Errorf("unable to get kubernetes cluster %s", cid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } if !poolFound { err := fmt.Errorf("unable to get kubernetes pool %s", search) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } return pool, nil } // DeleteKubernetesClusterPoolInstance implemented in a fake way for automated tests func (c *FakeClient) DeleteKubernetesClusterPoolInstance(cid, pid, id string) (*SimpleResponse, error) { clusterFound := false poolFound := false instanceFound := false for ci, cs := range c.Clusters { if cs.ID == cid { clusterFound = true for pi, p := range cs.Pools { if p.ID == pid { poolFound = true for i, in := range p.Instances { if in.ID == id { instanceFound = true p.Instances = append(p.Instances[:i], p.Instances[i+1:]...) instanceNames := []string{} for _, in := range p.Instances { instanceNames = append(instanceNames, in.Hostname) } p.InstanceNames = instanceNames c.Clusters[ci].Pools[pi] = p break } } } } } } if !clusterFound { err := fmt.Errorf("unable to get kubernetes cluster %s", cid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } if !poolFound { err := fmt.Errorf("unable to get kubernetes pool %s", pid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } if !instanceFound { err := fmt.Errorf("unable to get kubernetes pool instance %s", id) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } return &SimpleResponse{ Result: "success", }, nil } // UpdateKubernetesClusterPool implemented in a fake way for automated tests func (c *FakeClient) UpdateKubernetesClusterPool(cid, pid string, config *KubernetesClusterPoolUpdateConfig) (*KubernetesPool, error) { clusterFound := false poolFound := false pool := KubernetesPool{} for _, cs := range c.Clusters { if cs.ID == cid { clusterFound = true for _, p := range cs.Pools { if p.ID == pid { poolFound = true p.Count = config.Count pool = p } } } } if !clusterFound { err := fmt.Errorf("unable to get kubernetes cluster %s", cid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } if !poolFound { err := fmt.Errorf("unable to get kubernetes pool %s", pid) return nil, DatabaseKubernetesClusterNotFoundError.wrap(err) } return &pool, nil } // ListIPs returns a list of fake IPs func (c *FakeClient) ListIPs() (*PaginatedIPs, error) { return &PaginatedIPs{ Page: 1, PerPage: 20, Pages: 100, Items: []IP{ { ID: c.generateID(), Name: "test-ip", IP: c.generatePublicIP(), }, }, }, nil } // GetIP returns a fake IP func (c *FakeClient) GetIP(id string) (*IP, error) { return &IP{ ID: c.generateID(), Name: "test-ip", IP: c.generatePublicIP(), }, nil } // FindIP finds a fake IP func (c *FakeClient) FindIP(search string) (*IP, error) { return &IP{ ID: c.generateID(), Name: "test-ip", IP: c.generatePublicIP(), }, nil } // NewIP creates a fake IP func (c *FakeClient) NewIP(v *CreateIPRequest) (*IP, error) { return &IP{ ID: c.generateID(), Name: "test-ip", IP: c.generatePublicIP(), }, nil } // UpdateIP updates a fake IP func (c *FakeClient) UpdateIP(id string, v *UpdateIPRequest) (*IP, error) { return &IP{ ID: c.generateID(), Name: v.Name, IP: c.generatePublicIP(), }, nil } // DeleteIP deletes a fake IP func (c *FakeClient) DeleteIP(id string) (*SimpleResponse, error) { return &SimpleResponse{ Result: "success", }, nil } // AssignIP assigns a fake IP func (c *FakeClient) AssignIP(id, resourceID, resourceType, region string) (*SimpleResponse, error) { return &SimpleResponse{ Result: "success", }, nil } // UnassignIP unassigns a fake IP func (c *FakeClient) UnassignIP(id, region string) (*SimpleResponse, error) { return &SimpleResponse{ Result: "success", }, nil }