diff --git a/pkg/fixtures/hosts/dedicated_servers/feature_action_response.json b/pkg/fixtures/hosts/dedicated_servers/feature_action_response.json new file mode 100644 index 0000000..31304b0 --- /dev/null +++ b/pkg/fixtures/hosts/dedicated_servers/feature_action_response.json @@ -0,0 +1,4 @@ +{ + "name": "oob_public_access", + "status": "activation" +} diff --git a/pkg/fixtures/hosts/dedicated_servers/ssh_keys/attach_response.json b/pkg/fixtures/hosts/dedicated_servers/ssh_keys/attach_response.json new file mode 100644 index 0000000..476929d --- /dev/null +++ b/pkg/fixtures/hosts/dedicated_servers/ssh_keys/attach_response.json @@ -0,0 +1,11 @@ +[ + { + "name": "test-key", + "fingerprint": "48:81:0c:43:99:12:71:5e:ba:fd:e7:2f:20:d7:95:e8", + "labels": { + "env": "test" + }, + "updated_at": "2020-04-22T06:23:09Z", + "created_at": "2020-04-22T06:23:09Z" + } +] diff --git a/pkg/fixtures/hosts/dedicated_servers/ssh_keys/list_response.json b/pkg/fixtures/hosts/dedicated_servers/ssh_keys/list_response.json new file mode 100644 index 0000000..476929d --- /dev/null +++ b/pkg/fixtures/hosts/dedicated_servers/ssh_keys/list_response.json @@ -0,0 +1,11 @@ +[ + { + "name": "test-key", + "fingerprint": "48:81:0c:43:99:12:71:5e:ba:fd:e7:2f:20:d7:95:e8", + "labels": { + "env": "test" + }, + "updated_at": "2020-04-22T06:23:09Z", + "created_at": "2020-04-22T06:23:09Z" + } +] diff --git a/pkg/hosts.go b/pkg/hosts.go index 23e0c76..afe6d7e 100644 --- a/pkg/hosts.go +++ b/pkg/hosts.go @@ -17,20 +17,24 @@ const ( kubernetesBaremetalNodePrefix = "kubernetes_baremetal_nodes" sbmPrefix = "sbm_servers" - dedicatedServerCreatePath = "/hosts/dedicated_servers" - dedicatedServerPath = "/hosts/dedicated_servers/%s" - dedicatedServerScheduleReleasePath = "/hosts/dedicated_servers/%s/schedule_release" - dedicatedServerAbortReleasePath = "/hosts/dedicated_servers/%s/abort_release" - dedicatedServerPowerOnPath = "/hosts/dedicated_servers/%s/power_on" - dedicatedServerPowerOffPath = "/hosts/dedicated_servers/%s/power_off" - dedicatedServerPowerCyclePath = "/hosts/dedicated_servers/%s/power_cycle" - dedicatedServerPTRRecordCreatePath = "/hosts/dedicated_servers/%s/ptr_records" - dedicatedServerPTRRecordDeletePath = "/hosts/dedicated_servers/%s/ptr_records/%s" - dedicatedServerReinstallPath = "/hosts/dedicated_servers/%s/reinstall" - dedicatedServersListPath = "/hosts/dedicated_servers" - dedicatedServerServicesPath = "/hosts/dedicated_servers/%s/services" - dedicatedServerFeaturesPath = "/hosts/dedicated_servers/%s/features" - dedicatedServerOOBCredentialsPath = "/hosts/dedicated_servers/%s/oob_credentials" + dedicatedServerCreatePath = "/hosts/dedicated_servers" + dedicatedServerPath = "/hosts/dedicated_servers/%s" + dedicatedServerScheduleReleasePath = "/hosts/dedicated_servers/%s/schedule_release" + dedicatedServerAbortReleasePath = "/hosts/dedicated_servers/%s/abort_release" + dedicatedServerPowerOnPath = "/hosts/dedicated_servers/%s/power_on" + dedicatedServerPowerOffPath = "/hosts/dedicated_servers/%s/power_off" + dedicatedServerPowerCyclePath = "/hosts/dedicated_servers/%s/power_cycle" + dedicatedServerPTRRecordCreatePath = "/hosts/dedicated_servers/%s/ptr_records" + dedicatedServerPTRRecordDeletePath = "/hosts/dedicated_servers/%s/ptr_records/%s" + dedicatedServerReinstallPath = "/hosts/dedicated_servers/%s/reinstall" + dedicatedServersListPath = "/hosts/dedicated_servers" + dedicatedServerServicesPath = "/hosts/dedicated_servers/%s/services" + dedicatedServerFeaturesPath = "/hosts/dedicated_servers/%s/features" + dedicatedServerFeatureActivatePath = "/hosts/dedicated_servers/%s/features/%s/activate" + dedicatedServerFeatureDeactivatePath = "/hosts/dedicated_servers/%s/features/%s/deactivate" + dedicatedServerSSHKeysPath = "/hosts/dedicated_servers/%s/ssh_keys" + dedicatedServerSSHKeyPath = "/hosts/dedicated_servers/%s/ssh_keys/%s" + dedicatedServerOOBCredentialsPath = "/hosts/dedicated_servers/%s/oob_credentials" // ds networks dedicatedServerNetworkUsagePath = "/hosts/dedicated_servers/%s/network_utilization" @@ -119,6 +123,29 @@ type HostsService interface { PowerOffKubernetesBaremetalNode(ctx context.Context, id string) (*KubernetesBaremetalNode, error) PowerCycleKubernetesBaremetalNode(ctx context.Context, id string) (*KubernetesBaremetalNode, error) + // dedicated server feature activation / deactivation + ActivateDisaggregatedPublicPortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + DeactivateDisaggregatedPublicPortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + ActivateDisaggregatedPrivatePortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + DeactivateDisaggregatedPrivatePortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + ActivateNoPublicIpAddressFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + DeactivateNoPublicIpAddressFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + ActivateNoPrivateIpFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + DeactivateNoPrivateIpFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + ActivateOobPublicAccessFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + DeactivateOobPublicAccessFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + ActivateNoPublicNetworkFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + DeactivateNoPublicNetworkFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + ActivateHostRescueModeFeature(ctx context.Context, serverID string, input HostRescueModeFeatureInput) (*DedicatedServerFeature, error) + DeactivateHostRescueModeFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + ActivatePrivateIpxeBootFeature(ctx context.Context, serverID string, input PrivateIpxeBootFeatureInput) (*DedicatedServerFeature, error) + DeactivatePrivateIpxeBootFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) + + // dedicated server ssh keys + ListDedicatedServerSSHKeys(ctx context.Context, id string) ([]SSHKey, error) + AttachSSHKeysToDedicatedServer(ctx context.Context, id string, input SSHKeyAttachInput) ([]SSHKey, error) + DetachSSHKeyFromDedicatedServer(ctx context.Context, serverID, fingerprint string) error + // Additional collections DedicatedServerPowerFeeds(ctx context.Context, id string) ([]HostPowerFeed, error) DedicatedServerConnections(id string) Collection[HostConnection] @@ -898,6 +925,197 @@ func (h *HostsHandler) DedicatedServerFeatures(id string) Collection[DedicatedSe return NewCollection[DedicatedServerFeature](h.client, path) } +// activateFeature is an internal helper that calls POST .../features/{feature}/activate. +func (h *HostsHandler) activateFeature(ctx context.Context, serverID, feature string, payload []byte) (*DedicatedServerFeature, error) { + url := h.client.buildURL(dedicatedServerFeatureActivatePath, serverID, feature) + + body, err := h.client.buildAndExecRequest(ctx, "POST", url, payload) + if err != nil { + return nil, err + } + + result := new(DedicatedServerFeature) + if err := json.Unmarshal(body, result); err != nil { + return nil, err + } + + return result, nil +} + +// deactivateFeature is an internal helper that calls POST .../features/{feature}/deactivate. +func (h *HostsHandler) deactivateFeature(ctx context.Context, serverID, feature string) (*DedicatedServerFeature, error) { + url := h.client.buildURL(dedicatedServerFeatureDeactivatePath, serverID, feature) + + body, err := h.client.buildAndExecRequest(ctx, "POST", url, nil) + if err != nil { + return nil, err + } + + result := new(DedicatedServerFeature) + if err := json.Unmarshal(body, result); err != nil { + return nil, err + } + + return result, nil +} + +// ActivateDisaggregatedPublicPortsFeature activates the disaggregated_public_ports feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ActivateDisaggregatedPublicPortsFeatureForADedicatedServer +func (h *HostsHandler) ActivateDisaggregatedPublicPortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.activateFeature(ctx, serverID, "disaggregated_public_ports", nil) +} + +// DeactivateDisaggregatedPublicPortsFeature deactivates the disaggregated_public_ports feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateDisaggregatedPublicPortsFeatureForADedicatedServer +func (h *HostsHandler) DeactivateDisaggregatedPublicPortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "disaggregated_public_ports") +} + +// ActivateDisaggregatedPrivatePortsFeature activates the disaggregated_private_ports feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateDisaggregatedPrivatePortsFeatureForADedicatedServer +func (h *HostsHandler) ActivateDisaggregatedPrivatePortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.activateFeature(ctx, serverID, "disaggregated_private_ports", nil) +} + +// DeactivateDisaggregatedPrivatePortsFeature deactivates the disaggregated_private_ports feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateDisaggregatedPrivatePortsFeatureForADedicatedServer +func (h *HostsHandler) DeactivateDisaggregatedPrivatePortsFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "disaggregated_private_ports") +} + +// ActivateNoPublicIpAddressFeature activates the no_public_ip_address feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ActivateNoPublicIpAddressFeatureForADedicatedServer +func (h *HostsHandler) ActivateNoPublicIpAddressFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.activateFeature(ctx, serverID, "no_public_ip_address", nil) +} + +// DeactivateNoPublicIpAddressFeature deactivates the no_public_ip_address feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateNoPublicIpAddressFeatureForADedicatedServer +func (h *HostsHandler) DeactivateNoPublicIpAddressFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "no_public_ip_address") +} + +// ActivateNoPrivateIpFeature activates the no_private_ip feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ActivateNoPrivateIpFeatureForADedicatedServer +func (h *HostsHandler) ActivateNoPrivateIpFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.activateFeature(ctx, serverID, "no_private_ip", nil) +} + +// DeactivateNoPrivateIpFeature deactivates the no_private_ip feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateNoPrivateIpFeatureForADedicatedServer +func (h *HostsHandler) DeactivateNoPrivateIpFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "no_private_ip") +} + +// ActivateOobPublicAccessFeature activates the oob_public_access feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ActivateOobPublicAccessFeatureForADedicatedServer +func (h *HostsHandler) ActivateOobPublicAccessFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.activateFeature(ctx, serverID, "oob_public_access", nil) +} + +// DeactivateOobPublicAccessFeature deactivates the oob_public_access feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateOobPublicAccessFeatureForADedicatedServer +func (h *HostsHandler) DeactivateOobPublicAccessFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "oob_public_access") +} + +// ActivateNoPublicNetworkFeature activates the no_public_network feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ActivateNoPublicNetworkFeatureForADedicatedServer +func (h *HostsHandler) ActivateNoPublicNetworkFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.activateFeature(ctx, serverID, "no_public_network", nil) +} + +// DeactivateNoPublicNetworkFeature deactivates the no_public_network feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateNoPublicNetworkFeatureForADedicatedServer +func (h *HostsHandler) DeactivateNoPublicNetworkFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "no_public_network") +} + +// ActivateHostRescueModeFeature activates the host_rescue_mode feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ActivateHostRescueModeFeatureForADedicatedServer +func (h *HostsHandler) ActivateHostRescueModeFeature(ctx context.Context, serverID string, input HostRescueModeFeatureInput) (*DedicatedServerFeature, error) { + payload, err := json.Marshal(input) + if err != nil { + return nil, err + } + + return h.activateFeature(ctx, serverID, "host_rescue_mode", payload) +} + +// DeactivateHostRescueModeFeature deactivates the host_rescue_mode feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivateHostRescueModeFeatureForADedicatedServer +func (h *HostsHandler) DeactivateHostRescueModeFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "host_rescue_mode") +} + +// ActivatePrivateIpxeBootFeature activates the private_ipxe_boot feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ActivatePrivateIpxeBootFeatureForADedicatedServer +func (h *HostsHandler) ActivatePrivateIpxeBootFeature(ctx context.Context, serverID string, input PrivateIpxeBootFeatureInput) (*DedicatedServerFeature, error) { + payload, err := json.Marshal(input) + if err != nil { + return nil, err + } + + return h.activateFeature(ctx, serverID, "private_ipxe_boot", payload) +} + +// DeactivatePrivateIpxeBootFeature deactivates the private_ipxe_boot feature. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DeactivatePrivateIpxeBootFeatureForADedicatedServer +func (h *HostsHandler) DeactivatePrivateIpxeBootFeature(ctx context.Context, serverID string) (*DedicatedServerFeature, error) { + return h.deactivateFeature(ctx, serverID, "private_ipxe_boot") +} + +// ListDedicatedServerSSHKeys returns all SSH keys attached to a dedicated server. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/ListSshKeysForADedicatedServer +func (h *HostsHandler) ListDedicatedServerSSHKeys(ctx context.Context, id string) ([]SSHKey, error) { + url := h.client.buildURL(dedicatedServerSSHKeysPath, id) + + body, err := h.client.buildAndExecRequest(ctx, "GET", url, nil) + if err != nil { + return nil, err + } + + var keys []SSHKey + if err := json.Unmarshal(body, &keys); err != nil { + return nil, err + } + + return keys, nil +} + +// AttachSSHKeysToDedicatedServer attaches one or more SSH keys to a dedicated server. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/AttachSshKeysToADedicatedServer +func (h *HostsHandler) AttachSSHKeysToDedicatedServer(ctx context.Context, id string, input SSHKeyAttachInput) ([]SSHKey, error) { + payload, err := json.Marshal(input) + if err != nil { + return nil, err + } + + url := h.client.buildURL(dedicatedServerSSHKeysPath, id) + + body, err := h.client.buildAndExecRequest(ctx, "POST", url, payload) + if err != nil { + return nil, err + } + + var keys []SSHKey + if err := json.Unmarshal(body, &keys); err != nil { + return nil, err + } + + return keys, nil +} + +// DetachSSHKeyFromDedicatedServer removes a single SSH key from a dedicated server. +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/DetachAnSshKeyFromADedicatedServer +func (h *HostsHandler) DetachSSHKeyFromDedicatedServer(ctx context.Context, serverID, fingerprint string) error { + url := h.client.buildURL(dedicatedServerSSHKeyPath, serverID, fingerprint) + + _, err := h.client.buildAndExecRequest(ctx, "DELETE", url, nil) + + return err +} + // GetDedicatedServerOOBCredentials returns dedicated server OOB credentials // Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Dedicated-Server/operation/GetOobCredentialsForADedicatedServer func (h *HostsHandler) GetDedicatedServerOOBCredentials(ctx context.Context, id string, params map[string]string) (*DedicatedServerOOBCredentials, error) { diff --git a/pkg/hosts_test.go b/pkg/hosts_test.go index 05042b2..6b23832 100644 --- a/pkg/hosts_test.go +++ b/pkg/hosts_test.go @@ -1510,3 +1510,206 @@ func TestHostsDeletePTRRecordForSBMServer(t *testing.T) { g.Expect(err).To(BeNil()) } + +func TestActivateOobPublicAccessFeature(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/features/oob_public_access/activate"). + WithRequestMethod("POST"). + WithResponseBodyStubFile("fixtures/hosts/dedicated_servers/feature_action_response.json"). + WithResponseCode(202). + Build() + + defer ts.Close() + + ctx := context.TODO() + + feature, err := client.Hosts.ActivateOobPublicAccessFeature(ctx, serverID) + + g.Expect(err).To(BeNil()) + g.Expect(feature).ToNot(BeNil()) + g.Expect(feature.Name).To(Equal("oob_public_access")) + g.Expect(feature.Status).To(Equal("activation")) +} + +func TestDeactivateOobPublicAccessFeature(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/features/oob_public_access/deactivate"). + WithRequestMethod("POST"). + WithResponseBodyStubInline(`{"name":"oob_public_access","status":"deactivation"}`). + WithResponseCode(202). + Build() + + defer ts.Close() + + ctx := context.TODO() + + feature, err := client.Hosts.DeactivateOobPublicAccessFeature(ctx, serverID) + + g.Expect(err).To(BeNil()) + g.Expect(feature).ToNot(BeNil()) + g.Expect(feature.Status).To(Equal("deactivation")) +} + +func TestActivateHostRescueModeFeature(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/features/host_rescue_mode/activate"). + WithRequestMethod("POST"). + WithResponseBodyStubInline(`{"name":"host_rescue_mode","status":"activation"}`). + WithResponseCode(202). + Build() + + defer ts.Close() + + ctx := context.TODO() + + input := HostRescueModeFeatureInput{ + AuthMethods: []string{"password"}, + } + + feature, err := client.Hosts.ActivateHostRescueModeFeature(ctx, serverID, input) + + g.Expect(err).To(BeNil()) + g.Expect(feature).ToNot(BeNil()) + g.Expect(feature.Name).To(Equal("host_rescue_mode")) + g.Expect(feature.Status).To(Equal("activation")) +} + +func TestDeactivateHostRescueModeFeature(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/features/host_rescue_mode/deactivate"). + WithRequestMethod("POST"). + WithResponseBodyStubInline(`{"name":"host_rescue_mode","status":"deactivation"}`). + WithResponseCode(202). + Build() + + defer ts.Close() + + ctx := context.TODO() + + feature, err := client.Hosts.DeactivateHostRescueModeFeature(ctx, serverID) + + g.Expect(err).To(BeNil()) + g.Expect(feature).ToNot(BeNil()) + g.Expect(feature.Status).To(Equal("deactivation")) +} + +func TestActivatePrivateIpxeBootFeature(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/features/private_ipxe_boot/activate"). + WithRequestMethod("POST"). + WithResponseBodyStubInline(`{"name":"private_ipxe_boot","status":"activation"}`). + WithResponseCode(202). + Build() + + defer ts.Close() + + ctx := context.TODO() + + input := PrivateIpxeBootFeatureInput{IPXEConfig: "#!ipxe\nchain http://boot.example.com"} + + feature, err := client.Hosts.ActivatePrivateIpxeBootFeature(ctx, serverID, input) + + g.Expect(err).To(BeNil()) + g.Expect(feature).ToNot(BeNil()) + g.Expect(feature.Name).To(Equal("private_ipxe_boot")) +} + +func TestDeactivatePrivateIpxeBootFeature(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/features/private_ipxe_boot/deactivate"). + WithRequestMethod("POST"). + WithResponseBodyStubInline(`{"name":"private_ipxe_boot","status":"deactivation"}`). + WithResponseCode(202). + Build() + + defer ts.Close() + + ctx := context.TODO() + + feature, err := client.Hosts.DeactivatePrivateIpxeBootFeature(ctx, serverID) + + g.Expect(err).To(BeNil()) + g.Expect(feature).ToNot(BeNil()) + g.Expect(feature.Status).To(Equal("deactivation")) +} + +func TestListDedicatedServerSSHKeys(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/ssh_keys"). + WithRequestMethod("GET"). + WithResponseBodyStubFile("fixtures/hosts/dedicated_servers/ssh_keys/list_response.json"). + WithResponseCode(200). + Build() + + defer ts.Close() + + ctx := context.TODO() + + keys, err := client.Hosts.ListDedicatedServerSSHKeys(ctx, serverID) + + g.Expect(err).To(BeNil()) + g.Expect(keys).To(HaveLen(1)) + g.Expect(keys[0].Name).To(Equal("test-key")) + g.Expect(keys[0].Fingerprint).To(Equal(sshFingerprint)) + g.Expect(keys[0].Labels).To(Equal(map[string]string{"env": "test"})) + g.Expect(keys[0].Created.String()).To(Equal("2020-04-22 06:23:09 +0000 UTC")) + g.Expect(keys[0].Updated.String()).To(Equal("2020-04-22 06:23:09 +0000 UTC")) +} + +func TestAttachSSHKeysToDedicatedServer(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/ssh_keys"). + WithRequestMethod("POST"). + WithResponseBodyStubFile("fixtures/hosts/dedicated_servers/ssh_keys/attach_response.json"). + WithResponseCode(200). + Build() + + defer ts.Close() + + ctx := context.TODO() + + input := SSHKeyAttachInput{ + SSHKeyFingerprints: []string{sshFingerprint}, + } + + keys, err := client.Hosts.AttachSSHKeysToDedicatedServer(ctx, serverID, input) + + g.Expect(err).To(BeNil()) + g.Expect(keys).To(HaveLen(1)) + g.Expect(keys[0].Name).To(Equal("test-key")) + g.Expect(keys[0].Fingerprint).To(Equal(sshFingerprint)) +} + +func TestDetachSSHKeyFromDedicatedServer(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/hosts/dedicated_servers/"+serverID+"/ssh_keys/"+sshFingerprint). + WithRequestMethod("DELETE"). + WithResponseCode(204). + Build() + + defer ts.Close() + + ctx := context.TODO() + + err := client.Hosts.DetachSSHKeyFromDedicatedServer(ctx, serverID, sshFingerprint) + + g.Expect(err).To(BeNil()) +} diff --git a/pkg/types.go b/pkg/types.go index 120baed..439e153 100644 --- a/pkg/types.go +++ b/pkg/types.go @@ -435,6 +435,22 @@ type SSHKeyUpdateInput struct { Labels map[string]string `json:"labels,omitempty"` } +// SSHKeyAttachInput represents input for attaching SSH keys to a dedicated server +type SSHKeyAttachInput struct { + SSHKeyFingerprints []string `json:"ssh_key_fingerprints"` +} + +// HostRescueModeFeatureInput represents input for activating the host_rescue_mode feature +type HostRescueModeFeatureInput struct { + AuthMethods []string `json:"auth_methods"` + SSHKeyFingerprints []string `json:"ssh_key_fingerprints,omitempty"` +} + +// PrivateIpxeBootFeatureInput represents input for activating the private_ipxe_boot feature +type PrivateIpxeBootFeatureInput struct { + IPXEConfig string `json:"ipxe_config"` +} + // CloudComputingInstance represents cloud instance type CloudComputingInstance struct { Name string `json:"name"` @@ -948,8 +964,10 @@ type LoadBalancerCluster struct { // DedicatedServerUpdateInput represents dedicated server update input type DedicatedServerUpdateInput struct { - Labels map[string]string `json:"labels,omitempty"` - Title string `json:"title"` + Labels map[string]string `json:"labels,omitempty"` + Title string `json:"title,omitempty"` + UserData *string `json:"user_data,omitempty"` + IPXEConfig *string `json:"ipxe_config,omitempty"` } // KubernetesBaremetalNodeUpdateInput represents kubernetes baremetal node update input