diff --git a/doc/ovhcloud_cloud_rancher_edit.md b/doc/ovhcloud_cloud_rancher_edit.md index 7ae97ad..289139d 100644 --- a/doc/ovhcloud_cloud_rancher_edit.md +++ b/doc/ovhcloud_cloud_rancher_edit.md @@ -9,12 +9,11 @@ ovhcloud cloud rancher edit [flags] ### Options ``` - --editor Use a text editor to define parameters - -h, --help help for edit - --ip-restrictions stringArray List of IP restrictions (expected format: ',') - --name string Name of the managed Rancher service - --plan string Plan of the managed Rancher service (OVHCLOUD_EDITION, STANDARD) - --version string Version of the managed Rancher service + -h, --help help for edit + --iam-auth-enabled Allow Rancher to use identities managed by OVHcloud IAM (Identity and Access Management) to control access + --name string Name of the managed Rancher service + --plan string Plan of the managed Rancher service (OVHCLOUD_EDITION, STANDARD) + --version string Version of the managed Rancher service ``` ### Options inherited from parent commands diff --git a/internal/assets/api-schemas/cloud_v2.json b/internal/assets/api-schemas/cloud_v2.json index 3850a3f..6e4df4c 100644 --- a/internal/assets/api-schemas/cloud_v2.json +++ b/internal/assets/api-schemas/cloud_v2.json @@ -59,7 +59,8 @@ "ERROR", "PENDING", "RUNNING", - "SCHEDULED" + "SCHEDULED", + "WAITING_USER_INPUT" ] }, "common.Event": { @@ -239,7 +240,8 @@ "ERROR", "PENDING", "RUNNING", - "SCHEDULED" + "SCHEDULED", + "WAITING_USER_INPUT" ] }, "duration": { @@ -831,6 +833,10 @@ "type": "object", "description": "Target specification of the managed Rancher service", "properties": { + "iamAuthEnabled": { + "type": "boolean", + "description": "Allows Rancher to use identities managed by OVHcloud IAM (Identity and Access Management) to control access" + }, "name": { "type": "string", "description": "Name of the managed Rancher service" @@ -864,6 +870,12 @@ "format": "password", "readOnly": true }, + "iamAuthEnabled": { + "type": "boolean", + "description": "Allows Rancher to use identities managed by OVHcloud IAM (Identity and Access Management) to control access", + "nullable": true, + "readOnly": true + }, "ipRestrictions": { "type": "array", "description": "List of allowed CIDR blocks for a managed Rancher service's IP restrictions. When empty, any IP is allowed", @@ -933,6 +945,10 @@ "type": "object", "description": "Target specification of the managed Rancher service", "properties": { + "iamAuthEnabled": { + "type": "boolean", + "description": "Allows Rancher to use identities managed by OVHcloud IAM (Identity and Access Management) to control access" + }, "ipRestrictions": { "type": "array", "description": "List of allowed CIDR blocks for a managed Rancher service's IP restrictions. When empty, any IP is allowed", @@ -1122,6 +1138,25 @@ "format": "time", "example": "15:04:05" } + }, + "securitySchemes": { + "oAuth2AuthCode": { + "type": "oauth2", + "description": "Oauth2", + "x-client-id": "1bb9c7df371741c0", + "x-client-secret": "a5b4de870aca620d10fbf63cd18d205b", + "flows": { + "authorizationCode": { + "authorizationUrl": "https://www.ovh.com/auth/oauth2/authorize", + "tokenUrl": "https://www.ovh.com/auth/oauth2/token", + "scopes": { + "account/all": "Manage your account", + "all": "Manage your whole account and all your services", + "services/all": "Manage your services lifecycle and billing" + } + } + } + } } }, "paths": { @@ -1391,6 +1426,7 @@ { "createdAt": "2020-12-31T07:39:19Z", "currentState": { + "iamAuthEnabled": false, "ipRestrictions": [ { "cidrBlock": "198.51.100.1/32", @@ -1416,6 +1452,7 @@ "id": "d6b6579e-8d60-4487-bf08-8b4ddf98f7d3", "resourceStatus": "READY", "targetSpec": { + "iamAuthEnabled": false, "ipRestrictions": [ { "cidrBlock": "198.51.100.1/32", @@ -1431,6 +1468,7 @@ { "createdAt": "2020-12-31T13:37:46Z", "currentState": { + "iamAuthEnabled": false, "ipRestrictions": [], "name": "rancher2", "plan": "STANDARD", @@ -1448,6 +1486,7 @@ "id": "222ce105-a3f7-44c4-a7d3-dbb5983c045d", "resourceStatus": "UPDATING", "targetSpec": { + "iamAuthEnabled": false, "ipRestrictions": [], "name": "rancher2", "plan": "STANDARD", @@ -1539,6 +1578,7 @@ "Create a STANDARD managed Rancher on the latest version": { "value": { "targetSpec": { + "iamAuthEnabled": false, "name": "my_rancher", "plan": "STANDARD" } @@ -1548,6 +1588,7 @@ "Create an OVHCLOUD_EDITION managed Rancher on a specific version": { "value": { "targetSpec": { + "iamAuthEnabled": false, "name": "my_rancher", "plan": "OVHCLOUD_EDITION", "version": "1.0.0" @@ -1573,6 +1614,7 @@ "createdAt": "2020-12-31T07:39:19Z", "currentState": { "bootstrapPassword": "jL%IctBOu)-$D@wa", + "iamAuthEnabled": false, "ipRestrictions": [], "name": "my_rancher", "plan": "OVHCLOUD_EDITION", @@ -1589,6 +1631,7 @@ "id": "d6b6579e-8d60-4487-bf08-8b4ddf98f7d3", "resourceStatus": "CREATING", "targetSpec": { + "iamAuthEnabled": false, "ipRestrictions": [], "name": "my_rancher", "plan": "OVHCLOUD_EDITION", @@ -1691,6 +1734,7 @@ "value": { "createdAt": "2020-12-31T07:39:19Z", "currentState": { + "iamAuthEnabled": false, "ipRestrictions": [], "name": "my_rancher", "networking": { @@ -1717,6 +1761,7 @@ "id": "d6b6579e-8d60-4487-bf08-8b4ddf98f7d3", "resourceStatus": "DELETING", "targetSpec": { + "iamAuthEnabled": false, "ipRestrictions": [], "name": "my_rancher", "plan": "OVHCLOUD_EDITION", @@ -1817,6 +1862,7 @@ "value": { "createdAt": "2020-12-31T07:39:19Z", "currentState": { + "iamAuthEnabled": false, "ipRestrictions": [ { "cidrBlock": "198.51.100.1/32", @@ -1841,6 +1887,7 @@ "id": "d6b6579e-8d60-4487-bf08-8b4ddf98f7d3", "resourceStatus": "READY", "targetSpec": { + "iamAuthEnabled": false, "ipRestrictions": [ { "cidrBlock": "198.51.100.1/32", @@ -1945,6 +1992,7 @@ "Update rancher to plan STANDARD": { "value": { "targetSpec": { + "iamAuthEnabled": false, "name": "my_rancher", "plan": "STANDARD", "version": "1.0.0" @@ -1969,6 +2017,7 @@ "value": { "createdAt": "2020-12-31T07:39:19Z", "currentState": { + "iamAuthEnabled": false, "ipRestrictions": [], "name": "my_rancher", "networking": { @@ -1995,6 +2044,7 @@ "id": "d6b6579e-8d60-4487-bf08-8b4ddf98f7d3", "resourceStatus": "UPDATING", "targetSpec": { + "iamAuthEnabled": false, "ipRestrictions": [], "name": "my_rancher", "plan": "OVHCLOUD_EDITION", diff --git a/internal/cmd/cloud_rancher.go b/internal/cmd/cloud_rancher.go index fce7c43..39e331e 100644 --- a/internal/cmd/cloud_rancher.go +++ b/internal/cmd/cloud_rancher.go @@ -32,18 +32,7 @@ func initCloudRancherCommand(cloudCmd *cobra.Command) { Args: cobra.ExactArgs(1), }) - editRancherCmd := &cobra.Command{ - Use: "edit ", - Short: "Edit the given Rancher service", - Run: cloud.EditRancher, - Args: cobra.ExactArgs(1), - } - editRancherCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Name, "name", "", "Name of the managed Rancher service") - editRancherCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Plan, "plan", "", "Plan of the managed Rancher service (OVHCLOUD_EDITION, STANDARD)") - editRancherCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Version, "version", "", "Version of the managed Rancher service") - editRancherCmd.Flags().StringArrayVar(&cloud.RancherSpec.TargetSpec.CLIIPRestrictions, "ip-restrictions", nil, "List of IP restrictions (expected format: ',')") - addInteractiveEditorFlag(editRancherCmd) - rancherCmd.AddCommand(editRancherCmd) + rancherCmd.AddCommand(getRancherEditCmd()) rancherCmd.AddCommand(getRancherCreateCmd()) @@ -64,6 +53,38 @@ func initCloudRancherCommand(cloudCmd *cobra.Command) { cloudCmd.AddCommand(rancherCmd) } +func getRancherEditCmd() *cobra.Command { + editRancherCmd := &cobra.Command{ + Use: "edit ", + Short: "Edit the given Rancher service", + Run: cloud.EditRancher, + Args: cobra.ExactArgs(1), + } + + editRancherCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Name, "name", "", "Name of the managed Rancher service") + editRancherCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Plan, "plan", "", "Plan of the managed Rancher service (OVHCLOUD_EDITION, STANDARD)") + editRancherCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Version, "version", "", "Version of the managed Rancher service") + + var iamAuthEnabled bool + editRancherCmd.Flags().BoolVar(&iamAuthEnabled, "iam-auth-enabled", false, "Allow Rancher to use identities managed by OVHcloud IAM (Identity and Access Management) to control access") + cloud.RancherSpec.TargetSpec.IAMAuthEnabled = &iamAuthEnabled + + // Handle optional iam-auth-enabled boolean + editRancherCmd.PreRunE = func(cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("iam-auth-enabled") { + cloud.RancherSpec.TargetSpec.IAMAuthEnabled = &iamAuthEnabled + } else { + cloud.RancherSpec.TargetSpec.IAMAuthEnabled = nil + } + + return nil + } + + addInteractiveEditorFlag(editRancherCmd) + + return editRancherCmd +} + func getRancherCreateCmd() *cobra.Command { rancherCreateCmd := &cobra.Command{ Use: "create", @@ -112,7 +133,7 @@ There are three ways to define the creation parameters: rancherCreateCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Name, "name", "", "Name of the managed Rancher service") rancherCreateCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Plan, "plan", "", "Plan of the managed Rancher service (available plans can be listed using 'cloud reference rancher list-plans' command)") rancherCreateCmd.Flags().StringVar(&cloud.RancherSpec.TargetSpec.Version, "version", "", "Version of the managed Rancher service (available versions can be listed using 'cloud reference rancher list-versions' command)") - rancherCreateCmd.Flags().BoolVar(&cloud.RancherSpec.TargetSpec.IAMAuthEnabled, "iam-auth-enabled", false, "Allow Rancher to use identities managed by OVHcloud IAM (Identity and Access Management) to control access") + rancherCreateCmd.Flags().BoolVar(cloud.RancherSpec.TargetSpec.IAMAuthEnabled, "iam-auth-enabled", false, "Allow Rancher to use identities managed by OVHcloud IAM (Identity and Access Management) to control access") // Common flags for other means to define parameters addInitParameterFileFlag(rancherCreateCmd, assets.CloudV2OpenapiSchema, "/cloud/project/{serviceName}/rancher", "post", cloud.CloudRancherCreationExample, nil) diff --git a/internal/cmd/cloud_rancher_test.go b/internal/cmd/cloud_rancher_test.go index 0a7d7f0..4485838 100644 --- a/internal/cmd/cloud_rancher_test.go +++ b/internal/cmd/cloud_rancher_test.go @@ -20,6 +20,7 @@ func (ms *MockSuite) TestCloudRancherCreateCmd(assert, require *td.T) { tdhttpmock.JSONBody(td.JSON(` { "targetSpec": { + "iamAuthEnabled": false, "name": "test-rancher", "plan": "OVHCLOUD_EDITION", "version": "2.11.3" @@ -40,6 +41,7 @@ func (ms *MockSuite) TestCloudRancherCreateCmdJSONFormat(assert, require *td.T) tdhttpmock.JSONBody(td.JSON(` { "targetSpec": { + "iamAuthEnabled": false, "name": "test-rancher", "plan": "OVHCLOUD_EDITION", "version": "2.11.3" @@ -60,6 +62,7 @@ func (ms *MockSuite) TestCloudRancherCreateCmdYAMLFormat(assert, require *td.T) tdhttpmock.JSONBody(td.JSON(` { "targetSpec": { + "iamAuthEnabled": false, "name": "test-rancher", "plan": "OVHCLOUD_EDITION", "version": "2.11.3" @@ -83,6 +86,7 @@ func (ms *MockSuite) TestCloudRancherCreateCmdCustomFormat(assert, require *td.T tdhttpmock.JSONBody(td.JSON(` { "targetSpec": { + "iamAuthEnabled": false, "name": "test-rancher", "plan": "OVHCLOUD_EDITION", "version": "2.11.3" @@ -108,3 +112,45 @@ func (ms *MockSuite) TestCloudRancherResetAdminCredentialsCmd(assert, require *t assert.String(out, `✅ New Rancher service password for user admin: new-secret`) } + +func (ms *MockSuite) TestCloudRancherCreateCmdWithIamAuthEnabledTrue(assert, require *td.T) { + httpmock.RegisterMatcherResponder(http.MethodPost, + "https://eu.api.ovh.com/v2/publicCloud/project/fakeProjectID/rancher", + tdhttpmock.JSONBody(td.JSON(` + { + "targetSpec": { + "iamAuthEnabled": true, + "name": "test-rancher", + "plan": "OVHCLOUD_EDITION", + "version": "2.11.3" + } + }`), + ), + httpmock.NewStringResponder(200, `{"id": "rancher-12345"}`), + ) + + out, err := cmd.Execute("cloud", "rancher", "create", "--cloud-project", "fakeProjectID", "--name", "test-rancher", "--plan", "OVHCLOUD_EDITION", "--version", "2.11.3", "--iam-auth-enabled=true") + require.CmpNoError(err) + assert.String(out, `✅ Rancher test-rancher created successfully (id: rancher-12345)`) +} + +func (ms *MockSuite) TestCloudRancherCreateCmdWithIamAuthEnabledFalse(assert, require *td.T) { + httpmock.RegisterMatcherResponder(http.MethodPost, + "https://eu.api.ovh.com/v2/publicCloud/project/fakeProjectID/rancher", + tdhttpmock.JSONBody(td.JSON(` + { + "targetSpec": { + "iamAuthEnabled": false, + "name": "test-rancher", + "plan": "OVHCLOUD_EDITION", + "version": "2.11.3" + } + }`), + ), + httpmock.NewStringResponder(200, `{"id": "rancher-12345"}`), + ) + + out, err := cmd.Execute("cloud", "rancher", "create", "--cloud-project", "fakeProjectID", "--name", "test-rancher", "--plan", "OVHCLOUD_EDITION", "--version", "2.11.3", "--iam-auth-enabled=false") + require.CmpNoError(err) + assert.String(out, `✅ Rancher test-rancher created successfully (id: rancher-12345)`) +} diff --git a/internal/services/cloud/cloud_rancher.go b/internal/services/cloud/cloud_rancher.go index 643ca0a..2ed7e15 100644 --- a/internal/services/cloud/cloud_rancher.go +++ b/internal/services/cloud/cloud_rancher.go @@ -8,7 +8,6 @@ import ( _ "embed" "fmt" "net/url" - "strings" "github.com/ovh/ovhcloud-cli/internal/assets" "github.com/ovh/ovhcloud-cli/internal/display" @@ -29,21 +28,21 @@ var ( RancherSpec struct { TargetSpec struct { - IAMAuthEnabled bool `json:"iamAuthEnabled,omitempty"` - Name string `json:"name,omitempty"` - Plan string `json:"plan,omitempty"` - Version string `json:"version,omitempty"` - IPRestrictions []rancherIPRestriction `json:"ipRestrictions,omitempty"` - CLIIPRestrictions []string `json:"-"` + IAMAuthEnabled *bool `json:"iamAuthEnabled,omitempty"` + Name string `json:"name,omitempty"` + Plan string `json:"plan,omitempty"` + Version string `json:"version,omitempty"` + // IPRestrictions []rancherIPRestriction `json:"ipRestrictions,omitempty"` + // CLIIPRestrictions []string `json:"-"` } `json:"targetSpec"` } ) type ( - rancherIPRestriction struct { - CIDRBlock string `json:"cidrBlock"` - Description string `json:"description"` - } + //type rancherIPRestriction struct { + // CIDRBlock string `json:"cidrBlock"` + // Description string `json:"description"` + //} rancherUser struct { Username string `json:"username"` @@ -72,17 +71,17 @@ func GetRancher(_ *cobra.Command, args []string) { } func EditRancher(cmd *cobra.Command, args []string) { - for _, ipRestriction := range RancherSpec.TargetSpec.CLIIPRestrictions { - parts := strings.Split(ipRestriction, ",") - if len(parts) != 2 { - display.OutputError(&flags.OutputFormatConfig, "Invalid IP restriction format: %s. Expected format: ','", ipRestriction) - return - } - RancherSpec.TargetSpec.IPRestrictions = append(RancherSpec.TargetSpec.IPRestrictions, rancherIPRestriction{ - CIDRBlock: parts[0], - Description: parts[1], - }) - } + //for _, ipRestriction := range RancherSpec.TargetSpec.CLIIPRestrictions { + // parts := strings.Split(ipRestriction, ",") + // if len(parts) != 2 { + // display.OutputError(&flags.OutputFormatConfig, "Invalid IP restriction format: %s. Expected format: ','", ipRestriction) + // return + // } + // RancherSpec.TargetSpec.IPRestrictions = append(RancherSpec.TargetSpec.IPRestrictions, rancherIPRestriction{ + // CIDRBlock: parts[0], + // Description: parts[1], + // }) + //} projectID, err := getConfiguredCloudProject() if err != nil {