From fff0ab0a01ca1d10c9472889e449c157677b4549 Mon Sep 17 00:00:00 2001 From: Aaron Fischer Date: Mon, 2 Mar 2026 12:49:23 +0100 Subject: [PATCH 1/4] fix(node): add id parameter to node update action The node update action was missing the required 'id' parameter in its definition. This fix adds the id parameter (Node UUID) as a required field to the node.yaml definition, ensuring the update action can properly identify which node to update. Ticket: GPCO-8 --- pkg/generator/definition/node.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/generator/definition/node.yaml b/pkg/generator/definition/node.yaml index e4390b4..afc089d 100644 --- a/pkg/generator/definition/node.yaml +++ b/pkg/generator/definition/node.yaml @@ -38,7 +38,12 @@ actions: update: api-call: admin.UpdateNode description: Update node details + identifier: nil params: + - name: id + type: string + description: Node UUID + required: true - name: managed type: bool required: true From 2e7e4f5a0d7035151992b9ce675a5a7db0056a8c Mon Sep 17 00:00:00 2001 From: Aaron Fischer Date: Mon, 2 Mar 2026 13:01:10 +0100 Subject: [PATCH 2/4] fix(project): deprecate description and environment fields and fix generator enum handling Make description and environment optional in project create/update since they are deprecated in the proto (removal date 2025/03/01 already passed). Fix generator bug where non-required enum params incorrectly used pointer semantics for plain proto3 enum fields. Add explicit 'optional' YAML flag for proto oneof/optional pointer fields. - Mark project description/environment as deprecated and optional - Fix generator enum pointer handling in sub_command.go - Add Optional field to Param struct in definition.go - Mark image cloud_provider_type as optional (oneof pointer field) Ticket: GPCO-8 --- pkg/generator/definition.go | 1 + pkg/generator/definition/image.yaml | 1 + pkg/generator/definition/project.yaml | 30 +++++++++++++-------------- pkg/generator/sub_command.go | 13 ++++++++---- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/pkg/generator/definition.go b/pkg/generator/definition.go index 2868d6f..f58d3b4 100644 --- a/pkg/generator/definition.go +++ b/pkg/generator/definition.go @@ -32,6 +32,7 @@ type Param struct { Description string `yaml:"description"` Required bool `yaml:"required"` Default interface{} `yaml:"default"` + Optional bool `yaml:"optional"` // Proto field is a pointer type (oneof/optional) } type APICall struct { diff --git a/pkg/generator/definition/image.yaml b/pkg/generator/definition/image.yaml index a567944..1fa8ad3 100644 --- a/pkg/generator/definition/image.yaml +++ b/pkg/generator/definition/image.yaml @@ -25,6 +25,7 @@ actions: default: typev1.CLOUD_PROVIDER_TYPE_AWS description: Filter by cloud provider type required: false + optional: true fields: - Id - Name diff --git a/pkg/generator/definition/project.yaml b/pkg/generator/definition/project.yaml index 0ed9f5e..09c7db2 100644 --- a/pkg/generator/definition/project.yaml +++ b/pkg/generator/definition/project.yaml @@ -23,7 +23,6 @@ actions: description: Project ID required: true - # TODO: Fix after dependency upgrade update: api-call: cloud.UpdateProject description: Update project details @@ -32,23 +31,22 @@ actions: type: string description: Project name required: true - - name: description - type: string - description: Project description - required: true - - name: environment - type: cloudv1.ProjectEnvironment - description: Project environment - default: cloudv1.PROJECT_ENVIRONMENT_DEVELOPMENT - required: true - name: credit_card_id type: string description: Credit card ID required: true - name: billing_address_id type: string - description: Billing address ID + description: Billing profile ID required: true + - name: description + type: string + description: Project description (deprecated) + default: "" + - name: environment + type: cloudv1.ProjectEnvironment + description: Project environment (deprecated) + default: cloudv1.PROJECT_ENVIRONMENT_DEVELOPMENT create: api-call: cloud.CreateProject @@ -59,16 +57,18 @@ actions: type: string description: Project name required: true + - name: billing_address_id + type: string + description: Billing profile ID + required: true - name: description type: string + description: Project description (deprecated) default: "" - name: environment type: cloudv1.ProjectEnvironment + description: Project environment (deprecated) default: cloudv1.PROJECT_ENVIRONMENT_DEVELOPMENT - required: true - - name: billing_address_id - type: string - required: true delete: api-call: cloud.DeleteProject diff --git a/pkg/generator/sub_command.go b/pkg/generator/sub_command.go index 063185b..ac0c167 100644 --- a/pkg/generator/sub_command.go +++ b/pkg/generator/sub_command.go @@ -185,8 +185,11 @@ func runCommand(name string, metadata SubcommandMetadata) []Code { variable := strcase.LowerCamelCase(name) + title(strcase.LowerCamelCase(param.Name)) var val *Statement if isEnumType(param.Type) && !isArrayType(param.Type) { - // Enum helper function call - if !param.Required { + // Enum helper function call. Use a pointer when the proto field + // is explicitly marked as optional (oneof/optional pointer type). + if param.Optional { + // Variable is shadowed and converted before the API call, + // take its address for the pointer proto field. val = Op("&").Id(variable) } else { val = Qual("github.com/G-PORTAL/gpcore-cli/pkg/protobuf", stripPackage(param.Type)+"ToProto").Call(Id(variable)) @@ -213,9 +216,11 @@ func runCommand(name string, metadata SubcommandMetadata) []Code { respC := make([]Code, 0) - // Special variables for pointer usage + // For enum params marked as optional, the proto field is a pointer type + // (oneof/optional). We need to convert the string to the enum value and + // take its address. for _, param := range metadata.Action.Params { - if isEnumType(param.Type) && !param.Required { + if isEnumType(param.Type) && param.Optional { variable := strcase.LowerCamelCase(name) + title(strcase.LowerCamelCase(param.Name)) respC = append(respC, Id(variable). Op(":="). From 55244a0ff5e6771445d2e64b2383f46cd7ef1c69 Mon Sep 17 00:00:00 2001 From: Aaron Fischer Date: Mon, 2 Mar 2026 13:17:43 +0100 Subject: [PATCH 3/4] fix(network): disable network create command until ListSubnets endpoint available The network create command has been disabled because the ListSubnets endpoint is missing from the gRPC API. This endpoint is required to resolve subnet IDs provided by users. The command will be re-enabled once the admin.ListSubnets endpoint becomes available in the gRPC API. Key changes: - Replaced full implementation with documentation comments - Added TODO for re-enabling once ListSubnets is available - Noted the flag name fix needed (subnet-ids vs subnets) Ticket: GPCO-8 --- cmd/project/_network_create.go | 89 ++++------------------------------ 1 file changed, 9 insertions(+), 80 deletions(-) diff --git a/cmd/project/_network_create.go b/cmd/project/_network_create.go index 85247e9..61463b0 100644 --- a/cmd/project/_network_create.go +++ b/cmd/project/_network_create.go @@ -1,82 +1,11 @@ package project -import ( - "buf.build/gen/go/gportal/gpcore/grpc/go/gpcore/api/admin/v1/adminv1grpc" - adminv1 "buf.build/gen/go/gportal/gpcore/protocolbuffers/go/gpcore/api/admin/v1" - cloudv1 "buf.build/gen/go/gportal/gpcore/protocolbuffers/go/gpcore/api/cloud/v1" - "encoding/json" - "github.com/G-PORTAL/gpcore-cli/pkg/client" - "github.com/G-PORTAL/gpcore-cli/pkg/config" - "github.com/G-PORTAL/gpcore-cli/pkg/protobuf" - "github.com/spf13/cobra" - "google.golang.org/grpc" -) - -// This command is disabled at the moment because the ListSubnets endpoint is -// missing on gRPC (which is needed to get the subnets from the IDs). - -var networkCreateProjectId string -var networkCreateName string -var networkCreateType string -var networkCreateSubnets []string -var networkCreateVlanId int32 -var networkCreateDatacenter string - -var networkCreateCmd = &cobra.Command{ - Args: cobra.OnlyValidArgs, - DisableFlagsInUseLine: true, - Long: "", - RunE: func(cobraCmd *cobra.Command, args []string) error { - ctx := client.ExtractContext(cobraCmd) - grpcConn := ctx.Value("conn").(*grpc.ClientConn) - client := adminv1grpc.NewAdminServiceClient(grpcConn) - - networkCreateSubnetStructs := make([]*cloudv1.Subnet, 0) - // TODO: Get subnets from networkCreateSubnetUUIDList IDs - // TODO: ListSubnets endpoint missing on gRPC - - networkCreateDatacenterStruct := &cloudv1.Datacenter{ - Id: networkCreateDatacenter, - } - - resp, err := client.CreateProjectNetwork(cobraCmd.Context(), &adminv1.CreateProjectNetworkRequest{ - Name: networkCreateName, - ProjectId: networkCreateProjectId, - Subnets: networkCreateSubnetStructs, - Datacenter: networkCreateDatacenterStruct, - Type: protobuf.NetworkTypeToProto(networkCreateType), - VlanId: &networkCreateVlanId, - }) - if err != nil { - return err - } - respData := resp - if config.JSONOutput { - jsonData, err := protobuf.MarshalIndent(respData) - if err != nil { - return err - } - cobraCmd.Println(string(jsonData)) - } - return nil - }, - Short: "", - Use: "network-create", - ValidArgs: []string{"project-id", "name", "type", "subnet-ids", "datacenter-id", "vlan-id"}, -} - -func init() { - networkCreateCmd.Flags().StringVar(&networkCreateProjectId, "project-id", "", "Project ID (required)") - networkCreateCmd.Flags().StringVar(&networkCreateName, "name", "", "Network name (required)") - networkCreateCmd.Flags().StringVar(&networkCreateType, "type", "PRIVATE", "Network type (default:\"cloudv1.NETWORK_TYPE_PRIVATE\")") - networkCreateCmd.Flags().StringSliceVar(&networkCreateSubnets, "subnet-ids", []string{}, "Subnets (required)") - networkCreateCmd.Flags().StringVar(&networkCreateDatacenter, "datacenter-id", "", "Datacenter ID (required)") - networkCreateCmd.Flags().Int32Var(&networkCreateVlanId, "vlan-id", int32(0), "VLAN ID") - - networkCreateCmd.MarkFlagRequired("project-id") - networkCreateCmd.MarkFlagRequired("name") - networkCreateCmd.MarkFlagRequired("type") - networkCreateCmd.MarkFlagRequired("subnets") - - RootProjectCommand.AddCommand(networkCreateCmd) -} +// This command is disabled because the ListSubnets endpoint is missing on +// gRPC (which is needed to resolve subnet IDs). It will be re-enabled once +// the endpoint is available. +// +// TODO: Re-enable once admin.ListSubnets is available in the gRPC API. +// The command should: +// - Accept --subnet-ids and resolve them via ListSubnets +// - Register itself with RootProjectCommand.AddCommand(networkCreateCmd) +// - Fix MarkFlagRequired to use "subnet-ids" (not "subnets") From 06e603d5f62cbd59575583347fda17837aabeba7 Mon Sep 17 00:00:00 2001 From: Aaron Fischer Date: Mon, 2 Mar 2026 13:20:20 +0100 Subject: [PATCH 4/4] fix(cli): fix parameter descriptions and defaults across commands Correct misleading flag descriptions and defaults in several commands. - Fix network-arp mac_address description from "IP address" to "MAC address" - Make node reinstall user_data optional with empty default - Remove false "(required)" from rescue mode enabled/password descriptions Ticket: GPCO-8 --- cmd/node/change_rescue_mode.go | 4 ++-- pkg/generator/definition/network-arp.yaml | 2 +- pkg/generator/definition/node.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/node/change_rescue_mode.go b/cmd/node/change_rescue_mode.go index 5edf89d..11c44e5 100644 --- a/cmd/node/change_rescue_mode.go +++ b/cmd/node/change_rescue_mode.go @@ -52,8 +52,8 @@ var changeRescueModeCmd = &cobra.Command{ func init() { changeRescueModeCmd.Flags().StringVar(&changeRescueModeId, "id", "", "Node ID (required)") changeRescueModeCmd.Flags().StringVar(&changeRescueModeProjectId, "project-id", "", "Project ID (required)") - changeRescueModeCmd.Flags().BoolVar(&changeRescueModeEnabled, "enabled", false, "Enable or disable rescue mode (required)") - changeRescueModeCmd.Flags().StringVar(&changeRescueModePassword, "password", "", "Password for rescue mode (required)") + changeRescueModeCmd.Flags().BoolVar(&changeRescueModeEnabled, "enabled", false, "Enable or disable rescue mode") + changeRescueModeCmd.Flags().StringVar(&changeRescueModePassword, "password", "", "Password for rescue mode") changeRescueModeCmd.MarkFlagRequired("id") changeRescueModeCmd.MarkFlagRequired("project-id") diff --git a/pkg/generator/definition/network-arp.yaml b/pkg/generator/definition/network-arp.yaml index 7403624..78e84be 100644 --- a/pkg/generator/definition/network-arp.yaml +++ b/pkg/generator/definition/network-arp.yaml @@ -8,7 +8,7 @@ actions: params: - name: mac_address type: string - description: IP address + description: MAC address required: true list: diff --git a/pkg/generator/definition/node.yaml b/pkg/generator/definition/node.yaml index afc089d..16c8420 100644 --- a/pkg/generator/definition/node.yaml +++ b/pkg/generator/definition/node.yaml @@ -146,7 +146,7 @@ actions: - name: user_data type: string description: User data - required: true + default: "" power-action: api-call: cloud.PowerActionNode