diff --git a/cmd/entities/hosts/hosts.go b/cmd/entities/hosts/hosts.go index 7b0cf0a..3c0963a 100644 --- a/cmd/entities/hosts/hosts.go +++ b/cmd/entities/hosts/hosts.go @@ -56,6 +56,8 @@ func NewCmd(cmdContext *base.CmdContext) *cobra.Command { newGetEBMNetworkCmd, newAddEBMNetworkCmd, newDeleteEBMNetworkCmd, + newActivateEBMIPv6NetworkCmd, + newGetEBMNetworkUsageCmd, newListEBMCmd, newListEBMServicesCmd, newListEBMFeaturesCmd, @@ -94,6 +96,11 @@ func NewCmd(cmdContext *base.CmdContext) *cobra.Command { newUpdateSBMCmd, newSBMReleaseCmd, newListSBMCmd, + newListSBMNetworksCmd, + newGetSBMNetworkCmd, + newAddSBMNetworkCmd, + newDeleteSBMNetworkCmd, + newGetSBMNetworkUsageCmd, newListSBMPTRCmd, newCreateSBMPTRCmd, newDeleteSBMPTRCmd, diff --git a/cmd/entities/hosts/hosts_test.go b/cmd/entities/hosts/hosts_test.go index 1df8c34..5c772db 100644 --- a/cmd/entities/hosts/hosts_test.go +++ b/cmd/entities/hosts/hosts_test.go @@ -85,6 +85,8 @@ var ( } netTitle = "Some Net" cidr = "100.0.8.0/29" + netFirstIP = "100.0.8.2" + netGateway = "100.0.8.1" testNetwork = serverscom.Network{ ID: testNetworkId, Title: &netTitle, @@ -94,9 +96,19 @@ var ( InterfaceType: "public", DistributionMethod: "gateway", Additional: false, + FirstIP: &netFirstIP, + Gateway: &netGateway, Created: fixedTime, Updated: fixedTime, } + testNetworkUsage = serverscom.NetworkUsage{ + Type: "public", + Utilization: &serverscom.Utilization{ + Value: 100, + Commit: 50, + Unit: "GB", + }, + } testDriveModel = serverscom.DriveModel{ ID: int64(10), Name: "ssd-model-749", @@ -2492,6 +2504,623 @@ func TestListKBMNetworksCmd(t *testing.T) { } } +func TestGetSBMNetworkCmd(t *testing.T) { + testCases := []struct { + name string + id string + networkID string + output string + expectedOutput []byte + expectError bool + }{ + { + name: "get SBM network in default format", + id: testId, + networkID: testNetworkId, + output: "", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network.txt")), + }, + { + name: "get SBM network in JSON format", + id: testId, + networkID: testNetworkId, + output: "json", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network.json")), + }, + { + name: "get SBM network in YAML format", + id: testId, + networkID: testNetworkId, + output: "yaml", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network.yaml")), + }, + { + name: "get SBM network with error", + id: testId, + networkID: testNetworkId, + expectError: true, + }, + } + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + hostsServiceHandler := mocks.NewMockHostsService(mockCtrl) + scClient := serverscom.NewClientWithEndpoint("", "") + scClient.Hosts = hostsServiceHandler + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + var err error + if tc.expectError { + err = errors.New("some error") + } + hostsServiceHandler.EXPECT(). + GetSBMServerNetwork(gomock.Any(), tc.id, tc.networkID). + Return(&testNetwork, err) + + testCmdContext := testutils.NewTestCmdContext(scClient) + hostsCmd := NewCmd(testCmdContext) + + args := []string{ + "hosts", "sbm", "get-network", tc.id, + "--network-id", tc.networkID, + } + if tc.output != "" { + args = append(args, "--output", tc.output) + } + + builder := testutils.NewTestCommandBuilder(). + WithCommand(hostsCmd). + WithArgs(args) + + cmd := builder.Build() + err = cmd.Execute() + + if tc.expectError { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).To(BeNil()) + g.Expect(builder.GetOutput()).To(BeEquivalentTo(string(tc.expectedOutput))) + } + }) + } +} + +func TestListSBMNetworksCmd(t *testing.T) { + testNetwork1 := testNetwork + testNetwork1.ID = testNetworkId + testNetwork2 := testNetwork1 + testNetwork2.ID = "testNetId2" + netTitle2 := "Another Net" + testNetwork2.Title = &netTitle2 + + testCases := []struct { + name string + output string + args []string + expectedOutput []byte + expectError bool + configureMock func(*mocks.MockCollection[serverscom.Network]) + }{ + { + name: "list all SBM networks", + output: "json", + args: []string{"testServerId", "-A"}, + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "list_sbm_networks_all.json")), + configureMock: func(mock *mocks.MockCollection[serverscom.Network]) { + mock.EXPECT(). + Collect(gomock.Any()). + Return([]serverscom.Network{ + testNetwork1, + testNetwork2, + }, nil) + }, + }, + { + name: "list SBM networks", + output: "json", + args: []string{"testServerId"}, + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "list_sbm_networks.json")), + configureMock: func(mock *mocks.MockCollection[serverscom.Network]) { + mock.EXPECT(). + List(gomock.Any()). + Return([]serverscom.Network{ + testNetwork1, + }, nil) + }, + }, + { + name: "list SBM networks with template", + args: []string{"testServerId", "--template", "{{range .}}Network: {{.ID}} Title: {{.Title}}\n{{end}}"}, + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "list_sbm_networks_template.txt")), + configureMock: func(mock *mocks.MockCollection[serverscom.Network]) { + mock.EXPECT(). + List(gomock.Any()). + Return([]serverscom.Network{ + testNetwork1, + testNetwork2, + }, nil) + }, + }, + { + name: "list SBM networks with pageView", + args: []string{"testServerId", "--page-view"}, + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "list_sbm_networks_pageview.txt")), + configureMock: func(mock *mocks.MockCollection[serverscom.Network]) { + mock.EXPECT(). + List(gomock.Any()). + Return([]serverscom.Network{ + testNetwork1, + testNetwork2, + }, nil) + }, + }, + { + name: "list SBM networks with error", + args: []string{"testServerId"}, + expectError: true, + configureMock: func(mock *mocks.MockCollection[serverscom.Network]) { + mock.EXPECT(). + List(gomock.Any()). + Return(nil, errors.New("some error")) + }, + }, + } + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + hostsServiceHandler := mocks.NewMockHostsService(mockCtrl) + collectionHandler := mocks.NewMockCollection[serverscom.Network](mockCtrl) + + hostsServiceHandler.EXPECT(). + SBMServerNetworks(gomock.Any()). + Return(collectionHandler). + AnyTimes() + + collectionHandler.EXPECT(). + SetParam(gomock.Any(), gomock.Any()). + Return(collectionHandler). + AnyTimes() + + scClient := serverscom.NewClientWithEndpoint("", "") + scClient.Hosts = hostsServiceHandler + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + if tc.configureMock != nil { + tc.configureMock(collectionHandler) + } + + testCmdContext := testutils.NewTestCmdContext(scClient) + hostsCmd := NewCmd(testCmdContext) + + args := []string{"hosts", "sbm", "list-networks"} + if len(tc.args) > 0 { + args = append(args, tc.args...) + } + if tc.output != "" { + args = append(args, "--output", tc.output) + } + + builder := testutils.NewTestCommandBuilder(). + WithCommand(hostsCmd). + WithArgs(args) + + cmd := builder.Build() + + err := cmd.Execute() + + if tc.expectError { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).To(BeNil()) + g.Expect(builder.GetOutput()).To(BeEquivalentTo(string(tc.expectedOutput))) + } + }) + } +} + +func TestAddSBMNetworkCmd(t *testing.T) { + expectedInputPrivate := serverscom.NetworkInput{ + DistributionMethod: "gateway", + Mask: 29, + } + + testCases := []struct { + name string + output string + args []string + configureMock func(*mocks.MockHostsService) + expectedOutput []byte + expectError bool + }{ + { + name: "add private SBM network", + output: "json", + args: []string{ + testId, + "--type", "private", + "--mask", "29", + "--distribution-method", "gateway", + }, + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network.json")), + configureMock: func(mock *mocks.MockHostsService) { + mock.EXPECT(). + AddSBMServerPrivateIPv4Network(gomock.Any(), testId, expectedInputPrivate). + Return(&testNetwork, nil) + }, + }, + { + name: "add public SBM network is not supported", + args: []string{ + testId, + "--type", "public", + "--mask", "29", + }, + expectError: true, + }, + { + name: "add SBM network with unsupported mask", + args: []string{ + testId, + "--type", "private", + "--mask", "24", + }, + expectError: true, + }, + { + name: "add SBM network with error", + output: "json", + args: []string{ + testId, + "--type", "private", + "--mask", "29", + }, + expectError: true, + configureMock: func(mock *mocks.MockHostsService) { + mock.EXPECT(). + AddSBMServerPrivateIPv4Network(gomock.Any(), testId, expectedInputPrivate). + Return(nil, errors.New("some error")) + }, + }, + } + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + hostsServiceHandler := mocks.NewMockHostsService(mockCtrl) + + scClient := serverscom.NewClientWithEndpoint("", "") + scClient.Hosts = hostsServiceHandler + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + if tc.configureMock != nil { + tc.configureMock(hostsServiceHandler) + } + + testCmdContext := testutils.NewTestCmdContext(scClient) + hostsCmd := NewCmd(testCmdContext) + + args := append([]string{"hosts", "sbm", "add-network"}, tc.args...) + if tc.output != "" { + args = append(args, "--output", tc.output) + } + + builder := testutils.NewTestCommandBuilder(). + WithCommand(hostsCmd). + WithArgs(args) + + cmd := builder.Build() + + err := cmd.Execute() + + if tc.expectError { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).To(BeNil()) + g.Expect(builder.GetOutput()).To(BeEquivalentTo(string(tc.expectedOutput))) + } + }) + } +} + +func TestDeleteSBMNetworkCmd(t *testing.T) { + testCases := []struct { + name string + id string + networkID string + output string + expectedOutput []byte + expectError bool + }{ + { + name: "delete SBM network", + id: testId, + networkID: testNetworkId, + output: "json", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network.json")), + }, + { + name: "delete SBM network with error", + id: testId, + networkID: testNetworkId, + expectError: true, + }, + } + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + hostsServiceHandler := mocks.NewMockHostsService(mockCtrl) + + scClient := serverscom.NewClientWithEndpoint("", "") + scClient.Hosts = hostsServiceHandler + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + var err error + if tc.expectError { + err = errors.New("some error") + } + hostsServiceHandler.EXPECT(). + DeleteSBMServerNetwork(gomock.Any(), tc.id, tc.networkID). + Return(&testNetwork, err) + + testCmdContext := testutils.NewTestCmdContext(scClient) + hostsCmd := NewCmd(testCmdContext) + + args := []string{"hosts", "sbm", "delete-network", tc.id, "--network-id", tc.networkID} + if tc.output != "" { + args = append(args, "--output", tc.output) + } + + builder := testutils.NewTestCommandBuilder(). + WithCommand(hostsCmd). + WithArgs(args) + + cmd := builder.Build() + err = cmd.Execute() + + if tc.expectError { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).To(BeNil()) + g.Expect(builder.GetOutput()).To(BeEquivalentTo(string(tc.expectedOutput))) + } + }) + } +} + +func TestActivateEBMIPv6NetworkCmd(t *testing.T) { + testCases := []struct { + name string + id string + output string + expectedOutput []byte + expectError bool + }{ + { + name: "activate DS IPv6 network", + id: testId, + output: "json", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_ebm_network.json")), + }, + { + name: "activate DS IPv6 network with error", + id: testId, + expectError: true, + }, + } + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + hostsServiceHandler := mocks.NewMockHostsService(mockCtrl) + scClient := serverscom.NewClientWithEndpoint("", "") + scClient.Hosts = hostsServiceHandler + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + var err error + if tc.expectError { + err = errors.New("some error") + } + hostsServiceHandler.EXPECT(). + ActivateDedicatedServerPubliIPv6Network(gomock.Any(), tc.id). + Return(&testNetwork, err) + + testCmdContext := testutils.NewTestCmdContext(scClient) + hostsCmd := NewCmd(testCmdContext) + + args := []string{"hosts", "ebm", "activate-ipv6-network", tc.id} + if tc.output != "" { + args = append(args, "--output", tc.output) + } + + builder := testutils.NewTestCommandBuilder(). + WithCommand(hostsCmd). + WithArgs(args) + + cmd := builder.Build() + err = cmd.Execute() + + if tc.expectError { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).To(BeNil()) + g.Expect(builder.GetOutput()).To(BeEquivalentTo(string(tc.expectedOutput))) + } + }) + } +} + +func TestGetEBMNetworkUsageCmd(t *testing.T) { + testCases := []struct { + name string + id string + output string + expectedOutput []byte + expectError bool + }{ + { + name: "get DS network usage in default format", + id: testId, + output: "", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_ebm_network_usage.txt")), + }, + { + name: "get DS network usage in JSON format", + id: testId, + output: "json", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_ebm_network_usage.json")), + }, + { + name: "get DS network usage in YAML format", + id: testId, + output: "yaml", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_ebm_network_usage.yaml")), + }, + { + name: "get DS network usage with error", + id: testId, + expectError: true, + }, + } + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + hostsServiceHandler := mocks.NewMockHostsService(mockCtrl) + scClient := serverscom.NewClientWithEndpoint("", "") + scClient.Hosts = hostsServiceHandler + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + var err error + if tc.expectError { + err = errors.New("some error") + } + hostsServiceHandler.EXPECT(). + GetDedicatedServerNetworkUsage(gomock.Any(), tc.id). + Return(&testNetworkUsage, err) + + testCmdContext := testutils.NewTestCmdContext(scClient) + hostsCmd := NewCmd(testCmdContext) + + args := []string{"hosts", "ebm", "network-usage", tc.id} + if tc.output != "" { + args = append(args, "--output", tc.output) + } + + builder := testutils.NewTestCommandBuilder(). + WithCommand(hostsCmd). + WithArgs(args) + + cmd := builder.Build() + err = cmd.Execute() + + if tc.expectError { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).To(BeNil()) + g.Expect(builder.GetOutput()).To(BeEquivalentTo(string(tc.expectedOutput))) + } + }) + } +} + +func TestGetSBMNetworkUsageCmd(t *testing.T) { + testCases := []struct { + name string + id string + output string + expectedOutput []byte + expectError bool + }{ + { + name: "get SBM network usage in default format", + id: testId, + output: "", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network_usage.txt")), + }, + { + name: "get SBM network usage in JSON format", + id: testId, + output: "json", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network_usage.json")), + }, + { + name: "get SBM network usage in YAML format", + id: testId, + output: "yaml", + expectedOutput: testutils.ReadFixture(filepath.Join(fixtureBasePath, "get_sbm_network_usage.yaml")), + }, + { + name: "get SBM network usage with error", + id: testId, + expectError: true, + }, + } + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + hostsServiceHandler := mocks.NewMockHostsService(mockCtrl) + scClient := serverscom.NewClientWithEndpoint("", "") + scClient.Hosts = hostsServiceHandler + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + var err error + if tc.expectError { + err = errors.New("some error") + } + hostsServiceHandler.EXPECT(). + GetSBMServerNetworkUsage(gomock.Any(), tc.id). + Return(&testNetworkUsage, err) + + testCmdContext := testutils.NewTestCmdContext(scClient) + hostsCmd := NewCmd(testCmdContext) + + args := []string{"hosts", "sbm", "network-usage", tc.id} + if tc.output != "" { + args = append(args, "--output", tc.output) + } + + builder := testutils.NewTestCommandBuilder(). + WithCommand(hostsCmd). + WithArgs(args) + + cmd := builder.Build() + err = cmd.Execute() + + if tc.expectError { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).To(BeNil()) + g.Expect(builder.GetOutput()).To(BeEquivalentTo(string(tc.expectedOutput))) + } + }) + } +} + func TestListEBMDriveSlotsCmd(t *testing.T) { testDriveSlot1 := testDriveSlot testDriveSlot2 := testDriveSlot1 diff --git a/cmd/entities/hosts/networks.go b/cmd/entities/hosts/networks.go index 0d36cd8..3e57a29 100644 --- a/cmd/entities/hosts/networks.go +++ b/cmd/entities/hosts/networks.go @@ -1,6 +1,8 @@ package hosts import ( + "fmt" + serverscom "github.com/serverscom/serverscom-go-client/pkg" "github.com/serverscom/srvctl/cmd/base" "github.com/spf13/cobra" @@ -176,3 +178,242 @@ func newListKBMNetworksCmd(cmdContext *base.CmdContext) *cobra.Command { return cmd } + +func newListSBMNetworksCmd(cmdContext *base.CmdContext) *cobra.Command { + factory := func(verbose bool, args ...string) serverscom.Collection[serverscom.Network] { + scClient := cmdContext.GetClient().SetVerbose(verbose).GetScClient() + return scClient.Hosts.SBMServerNetworks(args[0]) + } + + opts := base.NewListOptions( + &base.BaseListOptions[serverscom.Network]{}, + &base.SearchPatternOption[serverscom.Network]{}, + &base.FamilyOption[serverscom.Network]{}, + &base.InterfaceTypeOption[serverscom.Network]{}, + &base.DistributionMethodOption[serverscom.Network]{}, + &base.AdditionalOption[serverscom.Network]{}, + ) + + cmd := base.NewListCmd("list-networks", "Scalable baremetal server networks", factory, cmdContext, opts...) + cmd.Use = "list-networks " + cmd.Args = cobra.ExactArgs(1) + + return cmd +} + +func newGetSBMNetworkCmd(cmdContext *base.CmdContext) *cobra.Command { + var networkID string + + cmd := &cobra.Command{ + Use: "get-network ", + Short: ("Get a scalable baremetal server network"), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + manager := cmdContext.GetManager() + ctx, cancel := base.SetupContext(cmd, manager) + defer cancel() + + base.SetupProxy(cmd, manager) + scClient := cmdContext.GetClient().SetVerbose(manager.GetVerbose(cmd)).GetScClient() + + id := args[0] + entity, err := scClient.Hosts.GetSBMServerNetwork(ctx, id, networkID) + if err != nil { + return err + } + + if entity != nil { + formatter := cmdContext.GetOrCreateFormatter(cmd) + return formatter.Format(entity) + } + return nil + }, + } + + cmd.Flags().StringVar(&networkID, "network-id", "", "Network id (required)") + _ = cmd.MarkFlagRequired("network-id") + + return cmd +} + +func newAddSBMNetworkCmd(cmdContext *base.CmdContext) *cobra.Command { + var ( + networkType string + mask int + distributionMethod string + ) + + cmd := &cobra.Command{ + Use: "add-network ", + Short: "Add private/public IPv4 network to scalable baremetal server", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + id := args[0] + + if err := validateNetworkArgs(networkType, distributionMethod, mask); err != nil { + return err + } + + input := serverscom.NetworkInput{ + DistributionMethod: distributionMethod, + Mask: mask, + } + + manager := cmdContext.GetManager() + ctx, cancel := base.SetupContext(cmd, manager) + defer cancel() + base.SetupProxy(cmd, manager) + scClient := cmdContext.GetClient().SetVerbose(manager.GetVerbose(cmd)).GetScClient() + + var entity *serverscom.Network + var err error + switch networkType { + case "public": + return fmt.Errorf("public networks currently are not supported for scalable baremetal servers") + case "private": + entity, err = scClient.Hosts.AddSBMServerPrivateIPv4Network(ctx, id, input) + } + if err != nil { + return err + } + if entity != nil { + formatter := cmdContext.GetOrCreateFormatter(cmd) + return formatter.Format(entity) + } + return nil + }, + } + + cmd.Flags().StringVar(&networkType, "type", "", "Network type: 'private'") + cmd.Flags().IntVar(&mask, "mask", 0, "Network mask (required)") + cmd.Flags().StringVar(&distributionMethod, "distribution-method", "gateway", "Distribution method ('gateway')") + _ = cmd.MarkFlagRequired("type") + _ = cmd.MarkFlagRequired("mask") + + return cmd +} + +func newDeleteSBMNetworkCmd(cmdContext *base.CmdContext) *cobra.Command { + var networkID string + + cmd := &cobra.Command{ + Use: "delete-network ", + Short: ("Delete a scalable baremetal server network"), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + manager := cmdContext.GetManager() + ctx, cancel := base.SetupContext(cmd, manager) + defer cancel() + + base.SetupProxy(cmd, manager) + scClient := cmdContext.GetClient().SetVerbose(manager.GetVerbose(cmd)).GetScClient() + + id := args[0] + entity, err := scClient.Hosts.DeleteSBMServerNetwork(ctx, id, networkID) + if err != nil { + return err + } + + if entity != nil { + formatter := cmdContext.GetOrCreateFormatter(cmd) + return formatter.Format(entity) + } + return nil + }, + } + + cmd.Flags().StringVar(&networkID, "network-id", "", "Network id (required)") + _ = cmd.MarkFlagRequired("network-id") + + return cmd +} + +func newActivateEBMIPv6NetworkCmd(cmdContext *base.CmdContext) *cobra.Command { + cmd := &cobra.Command{ + Use: "activate-ipv6-network ", + Short: ("Activate a public IPv6 network for an enterprise bare metal server"), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + manager := cmdContext.GetManager() + ctx, cancel := base.SetupContext(cmd, manager) + defer cancel() + + base.SetupProxy(cmd, manager) + scClient := cmdContext.GetClient().SetVerbose(manager.GetVerbose(cmd)).GetScClient() + + id := args[0] + entity, err := scClient.Hosts.ActivateDedicatedServerPubliIPv6Network(ctx, id) + if err != nil { + return err + } + + if entity != nil { + formatter := cmdContext.GetOrCreateFormatter(cmd) + return formatter.Format(entity) + } + return nil + }, + } + + return cmd +} + +func newGetEBMNetworkUsageCmd(cmdContext *base.CmdContext) *cobra.Command { + cmd := &cobra.Command{ + Use: "network-usage ", + Short: ("Get network utilization for an enterprise bare metal server"), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + manager := cmdContext.GetManager() + ctx, cancel := base.SetupContext(cmd, manager) + defer cancel() + + base.SetupProxy(cmd, manager) + scClient := cmdContext.GetClient().SetVerbose(manager.GetVerbose(cmd)).GetScClient() + + id := args[0] + entity, err := scClient.Hosts.GetDedicatedServerNetworkUsage(ctx, id) + if err != nil { + return err + } + + if entity != nil { + formatter := cmdContext.GetOrCreateFormatter(cmd) + return formatter.Format(entity) + } + return nil + }, + } + + return cmd +} + +func newGetSBMNetworkUsageCmd(cmdContext *base.CmdContext) *cobra.Command { + cmd := &cobra.Command{ + Use: "network-usage ", + Short: ("Get network utilization for a scalable baremetal server"), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + manager := cmdContext.GetManager() + ctx, cancel := base.SetupContext(cmd, manager) + defer cancel() + + base.SetupProxy(cmd, manager) + scClient := cmdContext.GetClient().SetVerbose(manager.GetVerbose(cmd)).GetScClient() + + id := args[0] + entity, err := scClient.Hosts.GetSBMServerNetworkUsage(ctx, id) + if err != nil { + return err + } + + if entity != nil { + formatter := cmdContext.GetOrCreateFormatter(cmd) + return formatter.Format(entity) + } + return nil + }, + } + + return cmd +} diff --git a/internal/output/entities/hosts.go b/internal/output/entities/hosts.go index 73e95b6..7b83886 100644 --- a/internal/output/entities/hosts.go +++ b/internal/output/entities/hosts.go @@ -17,6 +17,7 @@ var ( HostDriveSlotType = reflect.TypeFor[serverscom.HostDriveSlot]() HostPTRRecordType = reflect.TypeFor[serverscom.PTRRecord]() HostNetworkType = reflect.TypeFor[serverscom.Network]() + HostNetworkUsageType = reflect.TypeFor[serverscom.NetworkUsage]() HostFeatureType = reflect.TypeFor[serverscom.DedicatedServerFeature]() HostServiceType = reflect.TypeFor[serverscom.DedicatedServerService]() HostOOBCredsType = reflect.TypeFor[serverscom.DedicatedServerOOBCredentials]() @@ -25,7 +26,7 @@ var ( KubernetesBaremetalNodeListDefaultFields = []string{"ID", "KubernetesClusterNodeNumber", "Title", "LocationCode", "Status", "PublicIPv4Address"} SBMServerListDefaultFields = []string{"ID", "Title", "RackID", "LocationCode", "Status", "PublicIPv4Address"} - NetworkListDefaultFields = []string{"ID", "Title", "Status", "CIDR", "Family", "InterfaceType", "DistributionMethod", "Additional"} + NetworkListDefaultFields = []string{"ID", "Title", "Status", "CIDR", "Family", "InterfaceType", "DistributionMethod", "Additional", "FirstIP", "Gateway"} ) func getConfigurationDetailsField() Field { @@ -267,6 +268,8 @@ func RegisterHostsSubDefinitions() { {ID: "InterfaceType", Name: "InterfaceType", Path: "InterfaceType", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, {ID: "DistributionMethod", Name: "DistributionMethod", Path: "DistributionMethod", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, {ID: "Additional", Name: "Additional", Path: "Additional", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, + {ID: "FirstIP", Name: "FirstIP", Path: "FirstIP", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, + {ID: "Gateway", Name: "Gateway", Path: "Gateway", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, {ID: "Created", Name: "Created", Path: "Created", ListHandlerFunc: timeHandler, PageViewHandlerFunc: timeHandler, Default: true}, {ID: "Updated", Name: "Updated", Path: "Updated", ListHandlerFunc: timeHandler, PageViewHandlerFunc: timeHandler, Default: true}, }, @@ -279,6 +282,19 @@ func RegisterHostsSubDefinitions() { log.Fatal(err) } + hostNetworkUsageEntity := &Entity{ + fields: []Field{ + {ID: "Type", Name: "Type", Path: "Type", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, + {ID: "Value", Name: "Value", Path: "Utilization.Value", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, + {ID: "Commit", Name: "Commit", Path: "Utilization.Commit", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, + {ID: "Unit", Name: "Unit", Path: "Utilization.Unit", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, + }, + eType: HostNetworkUsageType, + } + if err := Registry.Register(hostNetworkUsageEntity); err != nil { + log.Fatal(err) + } + hostFeatureEntity := &Entity{ fields: []Field{ {ID: "Name", Name: "Name", Path: "Name", ListHandlerFunc: stringHandler, PageViewHandlerFunc: stringHandler, Default: true}, diff --git a/testdata/entities/hosts/get_ebm_network.json b/testdata/entities/hosts/get_ebm_network.json index 6b7ab4f..d0a5f89 100644 --- a/testdata/entities/hosts/get_ebm_network.json +++ b/testdata/entities/hosts/get_ebm_network.json @@ -7,6 +7,8 @@ "interface_type": "public", "distribution_method": "gateway", "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-01T12:00:00Z" } diff --git a/testdata/entities/hosts/get_ebm_network.txt b/testdata/entities/hosts/get_ebm_network.txt index 87fcf6f..0c2b290 100644 --- a/testdata/entities/hosts/get_ebm_network.txt +++ b/testdata/entities/hosts/get_ebm_network.txt @@ -1,2 +1,2 @@ -ID Title Status CIDR Family InterfaceType DistributionMethod Additional Created Updated -testNetId Some Net active 100.0.8.0/29 ipv4 public gateway false 2025-01-01T12:00:00Z 2025-01-01T12:00:00Z +ID Title Status CIDR Family InterfaceType DistributionMethod Additional FirstIP Gateway Created Updated +testNetId Some Net active 100.0.8.0/29 ipv4 public gateway false 100.0.8.2 100.0.8.1 2025-01-01T12:00:00Z 2025-01-01T12:00:00Z diff --git a/testdata/entities/hosts/get_ebm_network.yaml b/testdata/entities/hosts/get_ebm_network.yaml index 1def980..a5e0771 100644 --- a/testdata/entities/hosts/get_ebm_network.yaml +++ b/testdata/entities/hosts/get_ebm_network.yaml @@ -6,7 +6,7 @@ family: ipv4 interfacetype: public distributionmethod: gateway additional: false -firstip: null -gateway: null +firstip: 100.0.8.2 +gateway: 100.0.8.1 created: 2025-01-01T12:00:00Z updated: 2025-01-01T12:00:00Z diff --git a/testdata/entities/hosts/get_ebm_network_usage.json b/testdata/entities/hosts/get_ebm_network_usage.json new file mode 100644 index 0000000..1957b57 --- /dev/null +++ b/testdata/entities/hosts/get_ebm_network_usage.json @@ -0,0 +1,8 @@ +{ + "type": "public", + "utilization": { + "value": 100, + "commit": 50, + "unit": "GB" + } +} diff --git a/testdata/entities/hosts/get_ebm_network_usage.txt b/testdata/entities/hosts/get_ebm_network_usage.txt new file mode 100644 index 0000000..924c822 --- /dev/null +++ b/testdata/entities/hosts/get_ebm_network_usage.txt @@ -0,0 +1,2 @@ +Type Value Commit Unit +public 100 50 GB diff --git a/testdata/entities/hosts/get_ebm_network_usage.yaml b/testdata/entities/hosts/get_ebm_network_usage.yaml new file mode 100644 index 0000000..8636bdb --- /dev/null +++ b/testdata/entities/hosts/get_ebm_network_usage.yaml @@ -0,0 +1,5 @@ +type: public +utilization: + value: 100 + commit: 50 + unit: GB diff --git a/testdata/entities/hosts/get_sbm_network.json b/testdata/entities/hosts/get_sbm_network.json new file mode 100644 index 0000000..d0a5f89 --- /dev/null +++ b/testdata/entities/hosts/get_sbm_network.json @@ -0,0 +1,14 @@ +{ + "id": "testNetId", + "title": "Some Net", + "status": "active", + "cidr": "100.0.8.0/29", + "family": "ipv4", + "interface_type": "public", + "distribution_method": "gateway", + "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", + "created_at": "2025-01-01T12:00:00Z", + "updated_at": "2025-01-01T12:00:00Z" +} diff --git a/testdata/entities/hosts/get_sbm_network.txt b/testdata/entities/hosts/get_sbm_network.txt new file mode 100644 index 0000000..0c2b290 --- /dev/null +++ b/testdata/entities/hosts/get_sbm_network.txt @@ -0,0 +1,2 @@ +ID Title Status CIDR Family InterfaceType DistributionMethod Additional FirstIP Gateway Created Updated +testNetId Some Net active 100.0.8.0/29 ipv4 public gateway false 100.0.8.2 100.0.8.1 2025-01-01T12:00:00Z 2025-01-01T12:00:00Z diff --git a/testdata/entities/hosts/get_sbm_network.yaml b/testdata/entities/hosts/get_sbm_network.yaml new file mode 100644 index 0000000..a5e0771 --- /dev/null +++ b/testdata/entities/hosts/get_sbm_network.yaml @@ -0,0 +1,12 @@ +id: testNetId +title: Some Net +status: active +cidr: 100.0.8.0/29 +family: ipv4 +interfacetype: public +distributionmethod: gateway +additional: false +firstip: 100.0.8.2 +gateway: 100.0.8.1 +created: 2025-01-01T12:00:00Z +updated: 2025-01-01T12:00:00Z diff --git a/testdata/entities/hosts/get_sbm_network_usage.json b/testdata/entities/hosts/get_sbm_network_usage.json new file mode 100644 index 0000000..1957b57 --- /dev/null +++ b/testdata/entities/hosts/get_sbm_network_usage.json @@ -0,0 +1,8 @@ +{ + "type": "public", + "utilization": { + "value": 100, + "commit": 50, + "unit": "GB" + } +} diff --git a/testdata/entities/hosts/get_sbm_network_usage.txt b/testdata/entities/hosts/get_sbm_network_usage.txt new file mode 100644 index 0000000..924c822 --- /dev/null +++ b/testdata/entities/hosts/get_sbm_network_usage.txt @@ -0,0 +1,2 @@ +Type Value Commit Unit +public 100 50 GB diff --git a/testdata/entities/hosts/get_sbm_network_usage.yaml b/testdata/entities/hosts/get_sbm_network_usage.yaml new file mode 100644 index 0000000..8636bdb --- /dev/null +++ b/testdata/entities/hosts/get_sbm_network_usage.yaml @@ -0,0 +1,5 @@ +type: public +utilization: + value: 100 + commit: 50 + unit: GB diff --git a/testdata/entities/hosts/list_ebm_networks.json b/testdata/entities/hosts/list_ebm_networks.json index e2b6a08..8e36150 100644 --- a/testdata/entities/hosts/list_ebm_networks.json +++ b/testdata/entities/hosts/list_ebm_networks.json @@ -8,6 +8,8 @@ "interface_type": "public", "distribution_method": "gateway", "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-01T12:00:00Z" } diff --git a/testdata/entities/hosts/list_ebm_networks_all.json b/testdata/entities/hosts/list_ebm_networks_all.json index 1ffc14e..d79a5cc 100644 --- a/testdata/entities/hosts/list_ebm_networks_all.json +++ b/testdata/entities/hosts/list_ebm_networks_all.json @@ -8,6 +8,8 @@ "interface_type": "public", "distribution_method": "gateway", "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-01T12:00:00Z" }, @@ -20,6 +22,8 @@ "interface_type": "public", "distribution_method": "gateway", "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-01T12:00:00Z" } diff --git a/testdata/entities/hosts/list_ebm_networks_pageview.txt b/testdata/entities/hosts/list_ebm_networks_pageview.txt index a98985d..47471df 100644 --- a/testdata/entities/hosts/list_ebm_networks_pageview.txt +++ b/testdata/entities/hosts/list_ebm_networks_pageview.txt @@ -6,6 +6,8 @@ Family: ipv4 InterfaceType: public DistributionMethod: gateway Additional: false +FirstIP: 100.0.8.2 +Gateway: 100.0.8.1 Created: 2025-01-01T12:00:00Z Updated: 2025-01-01T12:00:00Z --- @@ -17,5 +19,7 @@ Family: ipv4 InterfaceType: public DistributionMethod: gateway Additional: false +FirstIP: 100.0.8.2 +Gateway: 100.0.8.1 Created: 2025-01-01T12:00:00Z Updated: 2025-01-01T12:00:00Z diff --git a/testdata/entities/hosts/list_kbm_networks.json b/testdata/entities/hosts/list_kbm_networks.json index e2b6a08..8e36150 100644 --- a/testdata/entities/hosts/list_kbm_networks.json +++ b/testdata/entities/hosts/list_kbm_networks.json @@ -8,6 +8,8 @@ "interface_type": "public", "distribution_method": "gateway", "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-01T12:00:00Z" } diff --git a/testdata/entities/hosts/list_kbm_networks_all.json b/testdata/entities/hosts/list_kbm_networks_all.json index 1ffc14e..d79a5cc 100644 --- a/testdata/entities/hosts/list_kbm_networks_all.json +++ b/testdata/entities/hosts/list_kbm_networks_all.json @@ -8,6 +8,8 @@ "interface_type": "public", "distribution_method": "gateway", "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-01T12:00:00Z" }, @@ -20,6 +22,8 @@ "interface_type": "public", "distribution_method": "gateway", "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", "created_at": "2025-01-01T12:00:00Z", "updated_at": "2025-01-01T12:00:00Z" } diff --git a/testdata/entities/hosts/list_kbm_networks_pageview.txt b/testdata/entities/hosts/list_kbm_networks_pageview.txt index a98985d..47471df 100644 --- a/testdata/entities/hosts/list_kbm_networks_pageview.txt +++ b/testdata/entities/hosts/list_kbm_networks_pageview.txt @@ -6,6 +6,8 @@ Family: ipv4 InterfaceType: public DistributionMethod: gateway Additional: false +FirstIP: 100.0.8.2 +Gateway: 100.0.8.1 Created: 2025-01-01T12:00:00Z Updated: 2025-01-01T12:00:00Z --- @@ -17,5 +19,7 @@ Family: ipv4 InterfaceType: public DistributionMethod: gateway Additional: false +FirstIP: 100.0.8.2 +Gateway: 100.0.8.1 Created: 2025-01-01T12:00:00Z Updated: 2025-01-01T12:00:00Z diff --git a/testdata/entities/hosts/list_sbm_networks.json b/testdata/entities/hosts/list_sbm_networks.json new file mode 100644 index 0000000..8e36150 --- /dev/null +++ b/testdata/entities/hosts/list_sbm_networks.json @@ -0,0 +1,16 @@ +[ + { + "id": "testNetId", + "title": "Some Net", + "status": "active", + "cidr": "100.0.8.0/29", + "family": "ipv4", + "interface_type": "public", + "distribution_method": "gateway", + "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", + "created_at": "2025-01-01T12:00:00Z", + "updated_at": "2025-01-01T12:00:00Z" + } +] diff --git a/testdata/entities/hosts/list_sbm_networks_all.json b/testdata/entities/hosts/list_sbm_networks_all.json new file mode 100644 index 0000000..d79a5cc --- /dev/null +++ b/testdata/entities/hosts/list_sbm_networks_all.json @@ -0,0 +1,30 @@ +[ + { + "id": "testNetId", + "title": "Some Net", + "status": "active", + "cidr": "100.0.8.0/29", + "family": "ipv4", + "interface_type": "public", + "distribution_method": "gateway", + "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", + "created_at": "2025-01-01T12:00:00Z", + "updated_at": "2025-01-01T12:00:00Z" + }, + { + "id": "testNetId2", + "title": "Another Net", + "status": "active", + "cidr": "100.0.8.0/29", + "family": "ipv4", + "interface_type": "public", + "distribution_method": "gateway", + "additional": false, + "first_ip": "100.0.8.2", + "gateway": "100.0.8.1", + "created_at": "2025-01-01T12:00:00Z", + "updated_at": "2025-01-01T12:00:00Z" + } +] diff --git a/testdata/entities/hosts/list_sbm_networks_pageview.txt b/testdata/entities/hosts/list_sbm_networks_pageview.txt new file mode 100644 index 0000000..47471df --- /dev/null +++ b/testdata/entities/hosts/list_sbm_networks_pageview.txt @@ -0,0 +1,25 @@ +ID: testNetId +Title: Some Net +Status: active +CIDR: 100.0.8.0/29 +Family: ipv4 +InterfaceType: public +DistributionMethod: gateway +Additional: false +FirstIP: 100.0.8.2 +Gateway: 100.0.8.1 +Created: 2025-01-01T12:00:00Z +Updated: 2025-01-01T12:00:00Z +--- +ID: testNetId2 +Title: Another Net +Status: active +CIDR: 100.0.8.0/29 +Family: ipv4 +InterfaceType: public +DistributionMethod: gateway +Additional: false +FirstIP: 100.0.8.2 +Gateway: 100.0.8.1 +Created: 2025-01-01T12:00:00Z +Updated: 2025-01-01T12:00:00Z diff --git a/testdata/entities/hosts/list_sbm_networks_template.txt b/testdata/entities/hosts/list_sbm_networks_template.txt new file mode 100644 index 0000000..8f58214 --- /dev/null +++ b/testdata/entities/hosts/list_sbm_networks_template.txt @@ -0,0 +1,2 @@ +Network: testNetId Title: Some Net +Network: testNetId2 Title: Another Net