From 8a618f77584e726dce3c4c7d1e68f36de55fb61d Mon Sep 17 00:00:00 2001 From: Stoyan Zhelyazkov Date: Thu, 11 Apr 2024 13:40:26 +0300 Subject: [PATCH] feat: Add VAPI bindings for guest namespaces and virtual machine classes Signed-off-by: Stoyan Zhelyazkov --- govc/USAGE.md | 166 ++++++++++++++++++++++++ govc/main.go | 2 + govc/namespace/create.go | 83 ++++++++++++ govc/namespace/info.go | 91 +++++++++++++ govc/namespace/ls.go | 87 +++++++++++++ govc/namespace/rm.go | 76 +++++++++++ govc/namespace/update.go | 84 ++++++++++++ govc/namespace/vmclass/create.go | 74 +++++++++++ govc/namespace/vmclass/info.go | 91 +++++++++++++ govc/namespace/vmclass/ls.go | 87 +++++++++++++ govc/namespace/vmclass/rm.go | 76 +++++++++++ govc/namespace/vmclass/update.go | 73 +++++++++++ govc/test/namespace.bats | 171 +++++++++++++++++++++++++ vapi/namespace/internal/internal.go | 5 +- vapi/namespace/namespace.go | 178 ++++++++++++++++++++++++++ vapi/namespace/simulator/simulator.go | 153 ++++++++++++++++++++++ 16 files changed, 1496 insertions(+), 1 deletion(-) create mode 100644 govc/namespace/create.go create mode 100644 govc/namespace/info.go create mode 100644 govc/namespace/ls.go create mode 100644 govc/namespace/rm.go create mode 100644 govc/namespace/update.go create mode 100644 govc/namespace/vmclass/create.go create mode 100644 govc/namespace/vmclass/info.go create mode 100644 govc/namespace/vmclass/ls.go create mode 100644 govc/namespace/vmclass/rm.go create mode 100644 govc/namespace/vmclass/update.go diff --git a/govc/USAGE.md b/govc/USAGE.md index 7a1590321..e8926a1b2 100644 --- a/govc/USAGE.md +++ b/govc/USAGE.md @@ -258,13 +258,23 @@ but appear via `govc $cmd -h`: - [namespace.cluster.disable](#namespaceclusterdisable) - [namespace.cluster.enable](#namespaceclusterenable) - [namespace.cluster.ls](#namespaceclusterls) + - [namespace.create](#namespacecreate) + - [namespace.info](#namespaceinfo) - [namespace.logs.download](#namespacelogsdownload) + - [namespace.ls](#namespacels) + - [namespace.rm](#namespacerm) - [namespace.service.activate](#namespaceserviceactivate) - [namespace.service.create](#namespaceservicecreate) - [namespace.service.deactivate](#namespaceservicedeactivate) - [namespace.service.info](#namespaceserviceinfo) - [namespace.service.ls](#namespaceservicels) - [namespace.service.rm](#namespaceservicerm) + - [namespace.update](#namespaceupdate) + - [namespace.vmclass.create](#namespacevmclasscreate) + - [namespace.vmclass.info](#namespacevmclassinfo) + - [namespace.vmclass.ls](#namespacevmclassls) + - [namespace.vmclass.rm](#namespacevmclassrm) + - [namespace.vmclass.update](#namespacevmclassupdate) - [object.collect](#objectcollect) - [object.destroy](#objectdestroy) - [object.method](#objectmethod) @@ -4271,6 +4281,41 @@ Options: -l=false Long listing format ``` +## namespace.create + +``` +Usage: govc namespace.create [OPTIONS] + +Creates a new vSphere Namespace on a Supervisor. + +Examples: + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7 + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,dca9cc16-9460-4da0-802c-4aa148ac6cf7 + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -vm-classes=best-effort-2xlarge + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -vm-classes=best-effort-2xlarge,best-effort-4xlarge + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,dca9cc16-9460-4da0-802c-4aa148ac6cf7 -vm-classes=best-effort-2xlarge,best-effort-4xlarge + +Options: + -content-libraries= The identifiers of the content libraries to associate with the vSphere Namespace. + -namespace= The name of the vSphere Namespace. + -supervisor= The identifier of the Supervisor. + -vm-classes= The identifiers of the virtual machine classes to associate with the vSphere Namespace. +``` + +## namespace.info + +``` +Usage: govc namespace.info [OPTIONS] NAME + +Displays the details of a vSphere Namespace. + +Examples: + govc namespace.info test-namespace + +Options: +``` + ## namespace.logs.download ``` @@ -4291,6 +4336,32 @@ Options: -cluster= Cluster [GOVC_CLUSTER] ``` +## namespace.ls + +``` +Usage: govc namespace.ls [OPTIONS] + +Displays the list of vSphere Namespaces. + +Examples: + govc namespace.ls + +Options: +``` + +## namespace.rm + +``` +Usage: govc namespace.rm [OPTIONS] NAME + +Deletes a vSphere Namespace. + +Examples: + govc namespace.rm test-namespace + +Options: +``` + ## namespace.service.activate ``` @@ -4373,6 +4444,101 @@ Examples: Options: ``` +## namespace.update + +``` +Usage: govc namespace.update [OPTIONS] NAME + +Modifies an existing vSphere Namespace on a Supervisor. + +Examples: + govc namespace.update -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7 test-namespace + govc namespace.update -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,617a3ee3-a2ff-4311-9a7c-0016ccf958bd test-namespace + govc namespace.update -vm-classes=best-effort-2xlarge test-namespace + govc namespace.update -vm-classes=best-effort-2xlarge,best-effort-4xlarge test-namespace + govc namespace.update -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,617a3ee3-a2ff-4311-9a7c-0016ccf958bd -vm-classes=best-effort-2xlarge,best-effort-4xlarge test-namespace + +Options: + -content-libraries= The list of content libraries to associate with the vSphere Namespace. + -vm-classes= The list of virtual machine classes to associate with the vSphere Namespace. +``` + +## namespace.vmclass.create + +``` +Usage: govc namespace.vmclass.create [OPTIONS] + +Creates a new virtual machine class. + + The name of the virtual machine class has DNS_LABEL restrictions + as specified in "https://tools.ietf.org/html/rfc1123". It + must be an alphanumeric (a-z and 0-9) string and with maximum length + of 63 characters and with the '-' character allowed anywhere except + the first or last character. This name is unique in this vCenter server. + +Examples: + govc namespace.vmclass.create -name=test-class-01 -cpus=8 -memory=8192 + +Options: + -cpus=0 The number of CPUs. + -memory=0 The amount of memory (in MB). + -name= The name of the virtual machine class. +``` + +## namespace.vmclass.info + +``` +Usage: govc namespace.vmclass.info [OPTIONS] NAME + +Displays the details of a virtual machine class. + +Examples: + govc namespace.vmclass.info test-class + +Options: +``` + +## namespace.vmclass.ls + +``` +Usage: govc namespace.vmclass.ls [OPTIONS] + +Displays the list of virtual machine classes. + +Examples: + govc namespace.vmclass.ls + +Options: +``` + +## namespace.vmclass.rm + +``` +Usage: govc namespace.vmclass.rm [OPTIONS] NAME + +Deletes a virtual machine class. + +Examples: + govc namespace.vmclass.rm test-class + +Options: +``` + +## namespace.vmclass.update + +``` +Usage: govc namespace.vmclass.update [OPTIONS] NAME + +Modifies an existing virtual machine class. + +Examples: + govc namespace.vmclass.update -cpus=8 -memory=8192 test-class + +Options: + -cpus=0 The number of CPUs. + -memory=0 The amount of memory (in MB). +``` + ## object.collect ``` diff --git a/govc/main.go b/govc/main.go index 592688499..f4f6fd272 100644 --- a/govc/main.go +++ b/govc/main.go @@ -80,8 +80,10 @@ import ( _ "github.com/vmware/govmomi/govc/ls" _ "github.com/vmware/govmomi/govc/metric" _ "github.com/vmware/govmomi/govc/metric/interval" + _ "github.com/vmware/govmomi/govc/namespace" _ "github.com/vmware/govmomi/govc/namespace/cluster" _ "github.com/vmware/govmomi/govc/namespace/service" + _ "github.com/vmware/govmomi/govc/namespace/vmclass" _ "github.com/vmware/govmomi/govc/object" _ "github.com/vmware/govmomi/govc/option" _ "github.com/vmware/govmomi/govc/permissions" diff --git a/govc/namespace/create.go b/govc/namespace/create.go new file mode 100644 index 000000000..ef19616ee --- /dev/null +++ b/govc/namespace/create.go @@ -0,0 +1,83 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package namespace + +import ( + "context" + "flag" + "strings" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/vapi/namespace" +) + +type create struct { + *flags.ClientFlag + + libraries string + vmClasses string + spec namespace.NamespacesInstanceCreateSpec +} + +func init() { + cli.Register("namespace.create", &create{}) +} + +func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + f.StringVar(&cmd.spec.Cluster, "supervisor", "", "The identifier of the Supervisor.") + f.StringVar(&cmd.spec.Namespace, "namespace", "", "The name of the vSphere Namespace.") + f.StringVar(&cmd.libraries, "content-libraries", "", "The identifiers of the content libraries to associate with the vSphere Namespace.") + f.StringVar(&cmd.vmClasses, "vm-classes", "", "The identifiers of the virtual machine classes to associate with the vSphere Namespace.") +} + +func (cmd *create) Process(ctx context.Context) error { + if len(cmd.libraries) > 0 { + cmd.spec.VmServiceSpec.ContentLibraries = strings.Split(cmd.libraries, ",") + } + if len(cmd.vmClasses) > 0 { + cmd.spec.VmServiceSpec.VmClasses = strings.Split(cmd.vmClasses, ",") + } + return cmd.ClientFlag.Process(ctx) +} + +func (cmd *create) Description() string { + return `Creates a new vSphere Namespace on a Supervisor. + +Examples: + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7 + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,dca9cc16-9460-4da0-802c-4aa148ac6cf7 + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -vm-classes=best-effort-2xlarge + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -vm-classes=best-effort-2xlarge,best-effort-4xlarge + govc namespace.create -namespace=test-namespace -supervisor=domain-c1 -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,dca9cc16-9460-4da0-802c-4aa148ac6cf7 -vm-classes=best-effort-2xlarge,best-effort-4xlarge` +} + +func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + return nm.CreateNamespace(ctx, cmd.spec) +} diff --git a/govc/namespace/info.go b/govc/namespace/info.go new file mode 100644 index 000000000..cac64f072 --- /dev/null +++ b/govc/namespace/info.go @@ -0,0 +1,91 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package namespace + +import ( + "context" + "flag" + "io" + + "github.com/vmware/govmomi/vapi/namespace" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" +) + +type infoResult namespace.NamespacesInstanceInfo + +func (r infoResult) Write(w io.Writer) error { + return nil +} + +type info struct { + *flags.ClientFlag + *flags.OutputFlag +} + +func init() { + cli.Register("namespace.info", &info{}) +} + +func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) +} + +func (cmd *info) Process(ctx context.Context) error { + if err := cmd.ClientFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + + return nil +} + +func (cmd *info) Usage() string { + return "NAME" +} + +func (cmd *info) Description() string { + return `Displays the details of a vSphere Namespace. + +Examples: + govc namespace.info test-namespace` +} + +func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + d, err := nm.GetNamespace(ctx, f.Arg(0)) + + if err != nil { + return err + } + + cmd.JSON = !cmd.All() + return cmd.WriteResult(infoResult(d)) +} diff --git a/govc/namespace/ls.go b/govc/namespace/ls.go new file mode 100644 index 000000000..b61aaefdb --- /dev/null +++ b/govc/namespace/ls.go @@ -0,0 +1,87 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package namespace + +import ( + "context" + "flag" + "io" + + "github.com/vmware/govmomi/vapi/namespace" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" +) + +type lsResult []namespace.NamespacesInstanceSummary + +func (r lsResult) Write(w io.Writer) error { + return nil +} + +type ls struct { + *flags.ClientFlag + *flags.OutputFlag +} + +func init() { + cli.Register("namespace.ls", &ls{}) +} + +func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) +} + +func (cmd *ls) Process(ctx context.Context) error { + if err := cmd.ClientFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + + return nil +} + +func (cmd *ls) Description() string { + return `Displays the list of vSphere Namespaces. + +Examples: + govc namespace.ls` +} + +func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + d, err := nm.ListNamespaces(ctx) + + if err != nil { + return err + } + + cmd.JSON = !cmd.All() + return cmd.WriteResult(lsResult(d)) +} diff --git a/govc/namespace/rm.go b/govc/namespace/rm.go new file mode 100644 index 000000000..a32ffcb4a --- /dev/null +++ b/govc/namespace/rm.go @@ -0,0 +1,76 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package namespace + +import ( + "context" + "flag" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/vapi/namespace" +) + +type rm struct { + *flags.ClientFlag + *flags.OutputFlag +} + +func init() { + cli.Register("namespace.rm", &rm{}) +} + +func (cmd *rm) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) +} + +func (cmd *rm) Process(ctx context.Context) error { + if err := cmd.ClientFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + + return nil +} + +func (cmd *rm) Usage() string { + return "NAME" +} + +func (cmd *rm) Description() string { + return `Deletes a vSphere Namespace. + +Examples: + govc namespace.rm test-namespace` +} + +func (cmd *rm) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + return nm.DeleteNamespace(ctx, f.Arg(0)) +} diff --git a/govc/namespace/update.go b/govc/namespace/update.go new file mode 100644 index 000000000..b88106905 --- /dev/null +++ b/govc/namespace/update.go @@ -0,0 +1,84 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package namespace + +import ( + "context" + "flag" + "strings" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/vapi/namespace" +) + +type update struct { + *flags.ClientFlag + + libraries string + vmClasses string + spec namespace.NamespacesInstanceUpdateSpec +} + +func init() { + cli.Register("namespace.update", &update{}) +} + +func (cmd *update) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + f.StringVar(&cmd.libraries, "content-libraries", "", "The list of content libraries to associate with the vSphere Namespace.") + f.StringVar(&cmd.vmClasses, "vm-classes", "", "The list of virtual machine classes to associate with the vSphere Namespace.") +} + +func (cmd *update) Process(ctx context.Context) error { + if len(cmd.libraries) > 0 { + cmd.spec.VmServiceSpec.ContentLibraries = strings.Split(cmd.libraries, ",") + } + if len(cmd.vmClasses) > 0 { + cmd.spec.VmServiceSpec.VmClasses = strings.Split(cmd.vmClasses, ",") + } + return cmd.ClientFlag.Process(ctx) +} + +func (cmd *update) Usage() string { + return "NAME" +} + +func (cmd *update) Description() string { + return `Modifies an existing vSphere Namespace on a Supervisor. + +Examples: + govc namespace.update -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7 test-namespace + govc namespace.update -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,617a3ee3-a2ff-4311-9a7c-0016ccf958bd test-namespace + govc namespace.update -vm-classes=best-effort-2xlarge test-namespace + govc namespace.update -vm-classes=best-effort-2xlarge,best-effort-4xlarge test-namespace + govc namespace.update -content-libraries=dca9cc16-9460-4da0-802c-4aa148ac6cf7,617a3ee3-a2ff-4311-9a7c-0016ccf958bd -vm-classes=best-effort-2xlarge,best-effort-4xlarge test-namespace` +} + +func (cmd *update) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + return nm.UpdateNamespace(ctx, f.Arg(0), cmd.spec) +} diff --git a/govc/namespace/vmclass/create.go b/govc/namespace/vmclass/create.go new file mode 100644 index 000000000..b30ae9d14 --- /dev/null +++ b/govc/namespace/vmclass/create.go @@ -0,0 +1,74 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vmclass + +import ( + "context" + "flag" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/vapi/namespace" +) + +type create struct { + *flags.ClientFlag + + spec namespace.VirtualMachineClassCreateSpec +} + +func init() { + cli.Register("namespace.vmclass.create", &create{}) +} + +func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + f.StringVar(&cmd.spec.Id, "name", "", "The name of the virtual machine class.") + f.Int64Var(&cmd.spec.CpuCount, "cpus", 0, "The number of CPUs.") + f.Int64Var(&cmd.spec.MemoryMb, "memory", 0, "The amount of memory (in MB).") +} + +func (cmd *create) Process(ctx context.Context) error { + return cmd.ClientFlag.Process(ctx) +} + +func (cmd *create) Description() string { + return `Creates a new virtual machine class. + + The name of the virtual machine class has DNS_LABEL restrictions + as specified in "https://tools.ietf.org/html/rfc1123". It + must be an alphanumeric (a-z and 0-9) string and with maximum length + of 63 characters and with the '-' character allowed anywhere except + the first or last character. This name is unique in this vCenter server. + +Examples: + govc namespace.vmclass.create -name=test-class-01 -cpus=8 -memory=8192` +} + +func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + return nm.CreateVmClass(ctx, cmd.spec) +} diff --git a/govc/namespace/vmclass/info.go b/govc/namespace/vmclass/info.go new file mode 100644 index 000000000..6cf965624 --- /dev/null +++ b/govc/namespace/vmclass/info.go @@ -0,0 +1,91 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vmclass + +import ( + "context" + "flag" + "io" + + "github.com/vmware/govmomi/vapi/namespace" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" +) + +type infoResult namespace.VirtualMachineClassInfo + +func (r infoResult) Write(w io.Writer) error { + return nil +} + +type info struct { + *flags.ClientFlag + *flags.OutputFlag +} + +func init() { + cli.Register("namespace.vmclass.info", &info{}) +} + +func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) +} + +func (cmd *info) Process(ctx context.Context) error { + if err := cmd.ClientFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + + return nil +} + +func (cmd *info) Usage() string { + return "NAME" +} + +func (cmd *info) Description() string { + return `Displays the details of a virtual machine class. + +Examples: + govc namespace.vmclass.info test-class` +} + +func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + d, err := nm.GetVmClass(ctx, f.Arg(0)) + + if err != nil { + return err + } + + cmd.JSON = !cmd.All() + return cmd.WriteResult(infoResult(d)) +} diff --git a/govc/namespace/vmclass/ls.go b/govc/namespace/vmclass/ls.go new file mode 100644 index 000000000..012991752 --- /dev/null +++ b/govc/namespace/vmclass/ls.go @@ -0,0 +1,87 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vmclass + +import ( + "context" + "flag" + "io" + + "github.com/vmware/govmomi/vapi/namespace" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" +) + +type lsResult []namespace.VirtualMachineClassInfo + +func (r lsResult) Write(w io.Writer) error { + return nil +} + +type ls struct { + *flags.ClientFlag + *flags.OutputFlag +} + +func init() { + cli.Register("namespace.vmclass.ls", &ls{}) +} + +func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) +} + +func (cmd *ls) Process(ctx context.Context) error { + if err := cmd.ClientFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + + return nil +} + +func (cmd *ls) Description() string { + return `Displays the list of virtual machine classes. + +Examples: + govc namespace.vmclass.ls` +} + +func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + d, err := nm.ListVmClasses(ctx) + + if err != nil { + return err + } + + cmd.JSON = !cmd.All() + return cmd.WriteResult(lsResult(d)) +} diff --git a/govc/namespace/vmclass/rm.go b/govc/namespace/vmclass/rm.go new file mode 100644 index 000000000..1ab6ed773 --- /dev/null +++ b/govc/namespace/vmclass/rm.go @@ -0,0 +1,76 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vmclass + +import ( + "context" + "flag" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/vapi/namespace" +) + +type rm struct { + *flags.ClientFlag + *flags.OutputFlag +} + +func init() { + cli.Register("namespace.vmclass.rm", &rm{}) +} + +func (cmd *rm) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) +} + +func (cmd *rm) Process(ctx context.Context) error { + if err := cmd.ClientFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + + return nil +} + +func (cmd *rm) Usage() string { + return "NAME" +} + +func (cmd *rm) Description() string { + return `Deletes a virtual machine class. + +Examples: + govc namespace.vmclass.rm test-class` +} + +func (cmd *rm) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + nm := namespace.NewManager(rc) + + return nm.DeleteVmClass(ctx, f.Arg(0)) +} diff --git a/govc/namespace/vmclass/update.go b/govc/namespace/vmclass/update.go new file mode 100644 index 000000000..5f91889e5 --- /dev/null +++ b/govc/namespace/vmclass/update.go @@ -0,0 +1,73 @@ +/* +Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vmclass + +import ( + "context" + "flag" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/vapi/namespace" +) + +type update struct { + *flags.ClientFlag + + spec namespace.VirtualMachineClassUpdateSpec +} + +func init() { + cli.Register("namespace.vmclass.update", &update{}) +} + +func (cmd *update) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + f.Int64Var(&cmd.spec.CpuCount, "cpus", 0, "The number of CPUs.") + f.Int64Var(&cmd.spec.MemoryMb, "memory", 0, "The amount of memory (in MB).") +} + +func (cmd *update) Process(ctx context.Context) error { + return cmd.ClientFlag.Process(ctx) +} + +func (cmd *update) Usage() string { + return "NAME" +} + +func (cmd *update) Description() string { + return `Modifies an existing virtual machine class. + +Examples: + govc namespace.vmclass.update -cpus=8 -memory=8192 test-class` +} + +func (cmd *update) Run(ctx context.Context, f *flag.FlagSet) error { + rc, err := cmd.RestClient() + + if err != nil { + return err + } + + cmd.spec.Id = f.Arg(0) + + nm := namespace.NewManager(rc) + + return nm.UpdateVmClass(ctx, cmd.spec.Id, cmd.spec) +} diff --git a/govc/test/namespace.bats b/govc/test/namespace.bats index a0bd7b170..e5cd7a9a8 100755 --- a/govc/test/namespace.bats +++ b/govc/test/namespace.bats @@ -112,5 +112,176 @@ load test_helper run govc namespace.service.info -json service2 assert_matches DE-ACTIVATED +} + +@test "namespace.create" { + vcsim_env + + run govc namespace.create -supervisor=domain-c1 -namespace=test-namespace-1 + assert_success + + ns=$(govc namespace.info test-namespace-1 | jq) + assert_equal "domain-c1" $(echo $ns | jq -r '."cluster"') + assert_equal "0" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"' | jq length) + + run govc namespace.create -supervisor=domain-c1 -namespace=test-namespace-2 -content-libraries=lib1,lib2 + assert_success + + ns=$(govc namespace.info test-namespace-2 | jq) + assert_equal "2" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"' | jq length) +} + +@test "namespace.update" { + vcsim_env + + govc namespace.create -supervisor=domain-c1 -namespace=test-namespace-1 + + run govc namespace.update -content-libraries=lib1,lib2 -vm-classes=class1 test-namespace-1 + assert_success + + ns=$(govc namespace.info test-namespace-1 | jq) + assert_equal "2" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"' | jq length) + assert_matches "lib[0-9]+" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"[0]') + assert_matches "lib[0-9]+" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"[1]') + assert_equal "1" $(echo $ns | jq -r '."vm_service_spec"."vm_classes"' | jq length) + assert_equal "class1" $(echo $ns | jq -r '."vm_service_spec"."vm_classes"[0]') + + run govc namespace.update -content-libraries=lib3 test-namespace-1 + assert_success + + ns=$(govc namespace.info test-namespace-1 | jq) + assert_equal "1" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"' | jq length) + assert_equal "lib3" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"[0]') + assert_equal "0" $(echo $ns | jq -r '."vm_service_spec"."vm_classes"' | jq length) + + run govc namespace.update -vm-classes=class3 test-namespace-1 + assert_success + + ns=$(govc namespace.info test-namespace-1 | jq) + assert_equal "0" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"' | jq length) + assert_equal "1" $(echo $ns | jq -r '."vm_service_spec"."vm_classes"' | jq length) + assert_equal "class3" $(echo $ns | jq -r '."vm_service_spec"."vm_classes"[0]') + + run govc namespace.update -content-libraries=lib4 -vm-classes=class4 test-namespace-1 + assert_success + + ns=$(govc namespace.info test-namespace-1 | jq) + assert_equal "1" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"' | jq length) + assert_equal "lib4" $(echo $ns | jq -r '."vm_service_spec"."content_libraries"[0]') + assert_equal "1" $(echo $ns | jq -r '."vm_service_spec"."vm_classes"' | jq length) + assert_equal "class4" $(echo $ns | jq -r '."vm_service_spec"."vm_classes"[0]') + + run govc namespace.update -content-libraries=lib1,lib2 -vm-classes=class1 non-existing-namespace + assert_failure + assert_matches "404 Not Found" +} + +@test "namespace.info" { + vcsim_env + + govc namespace.create -supervisor=domain-c1 -namespace=test-namespace-1 + + ns=$(govc namespace.info test-namespace-1 | jq) + assert_equal "domain-c1" $(echo $ns | jq -r '."cluster"') + run govc namespace.info non-existing-namespace + assert_failure + assert_matches "404 Not Found" +} + +@test "namespace.ls" { + vcsim_env + + ls=$(govc namespace.ls) + assert_equal "0" $(echo $ls | jq length) + + govc namespace.create -supervisor=domain-c1 -namespace=test-namespace-1 + ls=$(govc namespace.ls) + assert_equal "1" $(echo $ls | jq length) + assert_equal "test-namespace-1" $(echo $ls | jq -r '.[0]."namespace"') + + govc namespace.create -supervisor=domain-c1 -namespace=test-namespace-2 + ls=$(govc namespace.ls) + assert_equal "2" $(echo $ls | jq length) + assert_equal "domain-c1" $(echo $ls | jq -r '.[0]."cluster"') + assert_matches "test-namespace-[0-9]+" $(echo $ls | jq -r '.[0]."namespace"') + assert_equal "domain-c1" $(echo $ls | jq -r '.[1]."cluster"') + assert_matches "test-namespace-[0-9]+" $(echo $ls | jq -r '.[1]."namespace"') +} + +@test "namespace.rm" { + vcsim_env + + run govc namespace.rm non-existing-namespace + assert_failure + assert_matches "404 Not Found" + + govc namespace.create -supervisor=domain-c1 -namespace=test-namespace-1 + + run govc namespace.rm test-namespace-1 + assert_success +} + +@test "namespace.vmclass.create" { + vcsim_env + + run govc namespace.vmclass.create -name=test-class-1 -cpus=16 -memory=16000 + assert_success + + c=$(govc namespace.vmclass.info test-class-1 | jq) + assert_equal "16" $(echo $c | jq -r '."cpu_count"') + assert_equal "16000" $(echo $c | jq -r '."memory_mb"') +} + +@test "namespace.vmclass.update" { + vcsim_env + + govc namespace.vmclass.create -name=test-class-1 -cpus=16 -memory=16000 + + govc namespace.vmclass.update -cpus=24 -memory=24000 test-class-1 + c=$(govc namespace.vmclass.info test-class-1 | jq) + assert_equal "24" $(echo $c | jq -r '."cpu_count"') + assert_equal "24000" $(echo $c | jq -r '."memory_mb"') +} +@test "namespace.vmclass.info" { + vcsim_env + + run govc namespace.vmclass.create -name=test-class-1 -cpus=16 -memory=16000 + assert_success + + c=$(govc namespace.vmclass.info test-class-1 | jq) + assert_equal "16" $(echo $c | jq -r '."cpu_count"') + assert_equal "16000" $(echo $c | jq -r '."memory_mb"') + + run govc namespace.vmclass.info non-existing-class + assert_failure + assert_matches "404 Not Found" +} + +@test "namespace.vmclass.ls" { + vcsim_env + + ls=$(govc namespace.vmclass.ls) + assert_equal "0" $(echo $ls | jq length) + + govc namespace.vmclass.create -name=test-class-1 -cpus=16 -memory=16000 + ls=$(govc namespace.vmclass.ls) + assert_equal "1" $(echo $ls | jq length) + + govc namespace.vmclass.create -name=test-class-2 -cpus=16 -memory=16000 + ls=$(govc namespace.vmclass.ls) + assert_equal "2" $(echo $ls | jq length) +} + +@test "namespace.vmclass.rm" { + vcsim_env + + run govc namespace.vmclass.rm non-existing-class + assert_failure + assert_matches "404 Not Found" + + govc namespace.vmclass.create -name=test-class-1 -cpus=16 -memory=16000 + + run govc namespace.vmclass.rm test-class-1 + assert_success } \ No newline at end of file diff --git a/vapi/namespace/internal/internal.go b/vapi/namespace/internal/internal.go index b84e192ca..103caeaef 100644 --- a/vapi/namespace/internal/internal.go +++ b/vapi/namespace/internal/internal.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2020 VMware, Inc. All Rights Reserved. +Copyright (c) 2020-2024 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,6 +22,9 @@ const ( NamespaceDistributedSwitchCompatibility = "/api/vcenter/namespace-management/distributed-switch-compatibility" NamespaceEdgeClusterCompatibility = "/api/vcenter/namespace-management/edge-cluster-compatibility" SupervisorServicesPath = "/api/vcenter/namespace-management/supervisor-services" + + NamespacesPath = "/api/vcenter/namespaces/instances" + VmClassesPath = "/api/vcenter/namespace-management/virtual-machine-classes" ) type SupportBundleToken struct { diff --git a/vapi/namespace/namespace.go b/vapi/namespace/namespace.go index 7a1c8d30d..f54d94d9a 100644 --- a/vapi/namespace/namespace.go +++ b/vapi/namespace/namespace.go @@ -648,3 +648,181 @@ func (c *Manager) ListCompatibleEdgeClusters(ctx context.Context, clusterId stri WithPathEncodedParam("distributed_switch", switchId) return result, c.Do(ctx, listUrl.Request(http.MethodGet), &result) } + +// NamespacesInstanceStats https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/Stats/ +type NamespacesInstanceStats struct { + CpuUsed int64 `json:"cpu_used"` + MemoryUsed int64 `json:"memory_used"` + StorageUsed int64 `json:"storage_used"` +} + +// NamespacesInstanceSummary https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/Summary/ +type NamespacesInstanceSummary struct { + ClusterId string `json:"cluster"` + Namespace string `json:"namespace"` + ConfigStatus string `json:"config_status"` + Description string `json:"description"` + Stats NamespacesInstanceStats `json:"stats"` + SelfServiceNamespace bool `json:"self_service_namespace,omitempty"` +} + +type LocalizableMessage struct { + Details interface{} `json:"details"` + Severity string `json:"severity"` +} + +// NamespacesInstanceInfo https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/Info/ +type NamespacesInstanceInfo struct { + ClusterId string `json:"cluster"` + ConfigStatus string `json:"config_status"` + Description string `json:"description"` + Stats NamespacesInstanceStats `json:"stats"` + SelfServiceNamespace bool `json:"self_service_namespace,omitempty"` + Messages []LocalizableMessage `json:"message"` + VmServiceSpec VmServiceSpec `json:"vm_service_spec,omitempty"` +} + +// NamespacesInstanceCreateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/CreateSpec/ +type NamespacesInstanceCreateSpec struct { + Cluster string `json:"cluster"` + Namespace string `json:"namespace"` + VmServiceSpec VmServiceSpec `json:"vm_service_spec,omitempty"` +} + +// VmServiceSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/VMServiceSpec/ +type VmServiceSpec struct { + ContentLibraries []string `json:"content_libraries,omitempty"` + VmClasses []string `json:"vm_classes,omitempty"` +} + +// NamespacesInstanceUpdateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/UpdateSpec/ +type NamespacesInstanceUpdateSpec struct { + VmServiceSpec VmServiceSpec `json:"vm_service_spec,omitempty"` +} + +// ListNamespaces https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/get/ +func (c *Manager) ListNamespaces(ctx context.Context) ([]NamespacesInstanceSummary, error) { + resource := c.Resource(internal.NamespacesPath) + request := resource.Request(http.MethodGet) + var result []NamespacesInstanceSummary + return result, c.Do(ctx, request, &result) +} + +// GetNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/namespace/get/ +func (c *Manager) GetNamespace(ctx context.Context, namespace string) (NamespacesInstanceInfo, error) { + resource := c.Resource(internal.NamespacesPath).WithSubpath(namespace) + request := resource.Request(http.MethodGet) + var result NamespacesInstanceInfo + return result, c.Do(ctx, request, &result) +} + +// CreateNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/post/ +func (c *Manager) CreateNamespace(ctx context.Context, spec NamespacesInstanceCreateSpec) error { + resource := c.Resource(internal.NamespacesPath) + request := resource.Request(http.MethodPost, spec) + return c.Do(ctx, request, nil) +} + +// UpdateNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/namespace/patch/ +func (c *Manager) UpdateNamespace(ctx context.Context, namespace string, spec NamespacesInstanceUpdateSpec) error { + resource := c.Resource(internal.NamespacesPath).WithSubpath(namespace) + request := resource.Request(http.MethodPatch, spec) + return c.Do(ctx, request, nil) +} + +// DeleteNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/namespace/delete/ +func (c *Manager) DeleteNamespace(ctx context.Context, namespace string) error { + resource := c.Resource(internal.NamespacesPath).WithSubpath(namespace) + request := resource.Request(http.MethodDelete) + return c.Do(ctx, request, nil) +} + +// VirtualMachineClassInfo https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/Info/ +type VirtualMachineClassInfo struct { + ConfigStatus string `json:"config_status"` + Description string `json:"description"` + Id string `json:"id"` + CpuCount int64 `json:"cpu_count"` + MemoryMb int64 `json:"memory_mb"` + Messages []LocalizableMessage `json:"messages"` + Namespaces []string `json:"namespaces"` + Vms []string `json:"vms"` + Devices VirtualDevices `json:"devices"` + CpuReservation int64 `json:"cpu_reservation,omitempty"` + MemoryReservation int64 `json:"memory_reservation,omitempty"` +} + +// VirtualMachineClassCreateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/CreateSpec/ +type VirtualMachineClassCreateSpec struct { + Id string `json:"id"` + CpuCount int64 `json:"cpu_count"` + MemoryMb int64 `json:"memory_MB"` + CpuReservation int64 `json:"cpu_reservation,omitempty"` + MemoryReservation int64 `json:"memory_reservation,omitempty"` + Devices VirtualDevices `json:"devices"` +} + +// VirtualMachineClassUpdateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/UpdateSpec/ +type VirtualMachineClassUpdateSpec struct { + Id string `json:"id"` + CpuCount int64 `json:"cpu_count"` + MemoryMb int64 `json:"memory_MB"` + CpuReservation int64 `json:"cpu_reservation,omitempty"` + MemoryReservation int64 `json:"memory_reservation,omitempty"` + Devices VirtualDevices `json:"devices"` +} + +// DirectPathIoDevice https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/DynamicDirectPathIODevice/ +type DirectPathIoDevice struct { + CustomLabel string `json:"custom_label,omitempty"` + DeviceId int64 `json:"device_id"` + VendorId int64 `json:"vendor_id"` +} + +// VgpuDevice https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/VGPUDevice/ +type VgpuDevice struct { + ProfileName string `json:"profile_name"` +} + +// VirtualDevices https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/VirtualDevices/ +type VirtualDevices struct { + DirectPathIoDevices []DirectPathIoDevice `json:"direct_path_io_devices,omitempty"` + VgpuDevices []VgpuDevice `json:"vgpu_devices,omitempty"` +} + +// ListVmClasses https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/get/ +func (c *Manager) ListVmClasses(ctx context.Context) ([]VirtualMachineClassInfo, error) { + resource := c.Resource(internal.VmClassesPath) + request := resource.Request(http.MethodGet) + var result []VirtualMachineClassInfo + return result, c.Do(ctx, request, &result) +} + +// GetVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/vm_class/get/ +func (c *Manager) GetVmClass(ctx context.Context, vmClass string) (VirtualMachineClassInfo, error) { + resource := c.Resource(internal.VmClassesPath).WithSubpath(vmClass) + request := resource.Request(http.MethodGet) + var result VirtualMachineClassInfo + return result, c.Do(ctx, request, &result) +} + +// CreateVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/post/ +func (c *Manager) CreateVmClass(ctx context.Context, spec VirtualMachineClassCreateSpec) error { + resource := c.Resource(internal.VmClassesPath) + request := resource.Request(http.MethodPost, spec) + return c.Do(ctx, request, nil) +} + +// DeleteVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/vm_class/delete/ +func (c *Manager) DeleteVmClass(ctx context.Context, vmClass string) error { + resource := c.Resource(internal.VmClassesPath).WithSubpath(vmClass) + request := resource.Request(http.MethodDelete) + return c.Do(ctx, request, nil) +} + +// UpdateVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/vm_class/patch/ +func (c *Manager) UpdateVmClass(ctx context.Context, vmClass string, spec VirtualMachineClassUpdateSpec) error { + resource := c.Resource(internal.VmClassesPath).WithSubpath(vmClass) + request := resource.Request(http.MethodPatch, spec) + return c.Do(ctx, request, nil) +} diff --git a/vapi/namespace/simulator/simulator.go b/vapi/namespace/simulator/simulator.go index f568675d4..f992b6deb 100644 --- a/vapi/namespace/simulator/simulator.go +++ b/vapi/namespace/simulator/simulator.go @@ -24,6 +24,7 @@ import ( "net/http" "net/url" "path" + "strings" "time" "github.com/google/uuid" @@ -60,6 +61,8 @@ func New(u *url.URL) *Handler { // Register Namespace Management API paths with the vapi simulator's http.ServeMux func (h *Handler) Register(s *simulator.Service, r *simulator.Registry) { if r.IsVPX() { + s.HandleFunc(internal.NamespacesPath, h.namespaces) + s.HandleFunc(internal.NamespacesPath+"/", h.namespaces) s.HandleFunc(internal.NamespaceClusterPath, h.clusters) s.HandleFunc(internal.NamespaceClusterPath+"/", h.clustersID) s.HandleFunc(internal.NamespaceDistributedSwitchCompatibility+"/", h.listCompatibleDistributedSwitches) @@ -68,6 +71,8 @@ func (h *Handler) Register(s *simulator.Service, r *simulator.Registry) { s.HandleFunc(internal.SupervisorServicesPath, h.listServices) s.HandleFunc(internal.SupervisorServicesPath+"/", h.getService) + s.HandleFunc(internal.VmClassesPath, h.vmClasses) + s.HandleFunc(internal.VmClassesPath+"/", h.vmClasses) } } @@ -240,3 +245,151 @@ func (h *Handler) getService(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) } } + +var namespacesMap = make(map[string]*namespace.NamespacesInstanceInfo) + +func (h *Handler) namespaces(w http.ResponseWriter, r *http.Request) { + subpath := r.URL.Path[len(internal.NamespacesPath):] + subpath = strings.Replace(subpath, "/", "", -1) + + switch r.Method { + case http.MethodGet: + if len(subpath) > 0 { + if result, contains := namespacesMap[subpath]; contains { + vapi.StatusOK(w, result) + } else { + vapi.ApiErrorNotFound(w) + } + return + } else { + result := make([]namespace.NamespacesInstanceSummary, 0, len(namespacesMap)) + + for k, v := range namespacesMap { + entry := namespace.NamespacesInstanceSummary{ + ClusterId: v.ClusterId, + Namespace: k, + ConfigStatus: v.ConfigStatus, + Description: v.Description, + Stats: v.Stats, + } + result = append(result, entry) + } + + vapi.StatusOK(w, result) + } + case http.MethodPatch: + if len(subpath) > 0 { + if entry, contains := namespacesMap[subpath]; contains { + var spec namespace.NamespacesInstanceUpdateSpec + // If vapi.Decode fails it sets the status to bad request + if vapi.Decode(r, w, &spec) { + entry.VmServiceSpec = spec.VmServiceSpec + vapi.StatusOK(w) + } + } + } + + vapi.ApiErrorNotFound(w) + case http.MethodPost: + var spec namespace.NamespacesInstanceCreateSpec + // If vapi.Decode fails it sets the status to bad request + if !vapi.Decode(r, w, &spec) { + return + } + + newNamespace := namespace.NamespacesInstanceInfo{ + ClusterId: spec.Cluster, + ConfigStatus: namespace.RunningConfigStatus.String(), + VmServiceSpec: spec.VmServiceSpec, + } + + namespacesMap[spec.Namespace] = &newNamespace + + vapi.StatusOK(w) + case http.MethodDelete: + if len(subpath) > 0 { + if _, contains := namespacesMap[subpath]; contains { + delete(namespacesMap, subpath) + vapi.StatusOK(w) + return + } + } + vapi.ApiErrorNotFound(w) + } +} + +var vmClassesMap = make(map[string]*namespace.VirtualMachineClassInfo) + +func (h *Handler) vmClasses(w http.ResponseWriter, r *http.Request) { + subpath := r.URL.Path[len(internal.VmClassesPath):] + subpath = strings.Replace(subpath, "/", "", -1) + + switch r.Method { + case http.MethodGet: + if len(subpath) > 0 { + if result, contains := vmClassesMap[subpath]; contains { + vapi.StatusOK(w, result) + } else { + vapi.ApiErrorNotFound(w) + } + return + } else { + result := make([]*namespace.VirtualMachineClassInfo, 0, len(vmClassesMap)) + + for _, v := range vmClassesMap { + result = append(result, v) + } + + vapi.StatusOK(w, result) + } + case http.MethodPatch: + if len(subpath) > 0 { + if entry, contains := vmClassesMap[subpath]; contains { + var spec namespace.VirtualMachineClassUpdateSpec + // If vapi.Decode fails it sets the status to bad request + if !vapi.Decode(r, w, &spec) { + return + } + + entry.CpuCount = spec.CpuCount + entry.MemoryMb = spec.MemoryMb + entry.CpuReservation = spec.CpuReservation + entry.MemoryReservation = spec.MemoryReservation + entry.Devices = spec.Devices + + vapi.StatusOK(w) + return + } + } + + vapi.ApiErrorNotFound(w) + case http.MethodPost: + var spec namespace.VirtualMachineClassCreateSpec + // If vapi.Decode fails it sets the status to bad request + if !vapi.Decode(r, w, &spec) { + return + } + + newClass := namespace.VirtualMachineClassInfo{ + Id: spec.Id, + CpuCount: spec.CpuCount, + MemoryMb: spec.MemoryMb, + MemoryReservation: spec.MemoryReservation, + CpuReservation: spec.CpuReservation, + Devices: spec.Devices, + } + + vmClassesMap[spec.Id] = &newClass + + vapi.StatusOK(w) + case http.MethodDelete: + if len(subpath) > 0 { + if _, contains := vmClassesMap[subpath]; contains { + delete(vmClassesMap, subpath) + vapi.StatusOK(w) + return + } + } + vapi.ApiErrorNotFound(w) + } +}