diff --git a/cmd/capibmadm/cmd/vpc/key/create.go b/cmd/capibmadm/cmd/vpc/key/create.go new file mode 100644 index 000000000..fd6690266 --- /dev/null +++ b/cmd/capibmadm/cmd/vpc/key/create.go @@ -0,0 +1,122 @@ +/* +Copyright 2023 The Kubernetes Authors. + +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 key + +import ( + "context" + "fmt" + "os" + + "github.com/spf13/cobra" + "golang.org/x/crypto/ssh" + + "github.com/IBM/vpc-go-sdk/vpcv1" + + logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log" + + "sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/iam" + "sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/vpc" + "sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/options" + "sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/utils" +) + +type keyCreateOptions struct { + name string + publicKey string + resourceGroupName string +} + +// CreateCommand vpc key create command. +func CreateCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "create", + Short: "Create VPC key", + Example: ` +# Create key in VPC +export IBMCLOUD_API_KEY= +capibmadm vpc key create --name --region --public-key "" +Using file-path to SSH key : capibmadm vpc key create --name --region --key-path +`, + } + + options.AddCommonFlags(cmd) + var keyCreateOption keyCreateOptions + var filePath string + cmd.Flags().StringVar(&keyCreateOption.name, "name", keyCreateOption.name, "Key Name") + cmd.Flags().StringVar(&filePath, "key-path", "", "The absolute path to the SSH key file.") + cmd.Flags().StringVar(&keyCreateOption.publicKey, "public-key", keyCreateOption.publicKey, "Public Key") + _ = cmd.MarkFlagRequired("name") + // TODO: Flag validation is handled in PreRunE until the support for MarkFlagsMutuallyExclusiveAndRequired is available. + // Related issue: https://github.com/spf13/cobra/issues/1216 + cmd.PreRunE = func(cmd *cobra.Command, args []string) error { + if (keyCreateOption.publicKey == "") == (filePath == "") { + return fmt.Errorf("the required flags either key-path of SSH key or the public-key within double quotation marks is not found") + } + return nil + } + cmd.RunE = func(cmd *cobra.Command, args []string) error { + if filePath != "" { + sshKey, err := os.ReadFile(filePath) // #nosec + if err != nil { + return fmt.Errorf("error while reading the SSH key from path. %w", err) + } + keyCreateOption.publicKey = string(sshKey) + } + + if _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(keyCreateOption.publicKey)); err != nil { + return fmt.Errorf("the provided SSH key is invalid. %w ", err) + } + return createKey(cmd.Context(), keyCreateOption) + } + return cmd +} + +func createKey(ctx context.Context, keyCreateOption keyCreateOptions) error { + log := logf.Log + vpcClient, err := vpc.NewV1Client(options.GlobalOptions.VPCRegion) + if err != nil { + return err + } + + accountID, err := utils.GetAccountID(ctx, iam.GetIAMAuth()) + if err != nil { + return err + } + + options := &vpcv1.CreateKeyOptions{} + + options.SetName(keyCreateOption.name) + options.SetPublicKey(keyCreateOption.publicKey) + + if keyCreateOption.resourceGroupName != "" { + resourceGroupID, err := utils.GetResourceGroupID(ctx, keyCreateOption.resourceGroupName, accountID) + if err != nil { + return err + } + resourceGroup := &vpcv1.ResourceGroupIdentity{ + ID: &resourceGroupID, + } + options.SetResourceGroup(resourceGroup) + } + + key, _, err := vpcClient.CreateKey(options) + if err != nil { + return err + } + log.Info("SSH Key created successfully,", "key-name", *key.Name) + return nil +} diff --git a/cmd/capibmadm/cmd/vpc/key/delete.go b/cmd/capibmadm/cmd/vpc/key/delete.go new file mode 100644 index 000000000..6768854eb --- /dev/null +++ b/cmd/capibmadm/cmd/vpc/key/delete.go @@ -0,0 +1,100 @@ +/* +Copyright 2023 The Kubernetes Authors. + +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 key + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/IBM/vpc-go-sdk/vpcv1" + + logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log" + + "sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/vpc" + "sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/options" +) + +type keyDeleteOptions struct { + name string +} + +// DeleteCommand vpc key delete command. +func DeleteCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete VPC key", + Example: ` +# Delete key in VPC +export IBMCLOUD_API_KEY= +capibmadm vpc key delete --name --region `, + } + + options.AddCommonFlags(cmd) + var keyDeleteOption keyDeleteOptions + cmd.Flags().StringVar(&keyDeleteOption.name, "name", keyDeleteOption.name, "Key Name") + _ = cmd.MarkFlagRequired("name") + cmd.RunE = func(cmd *cobra.Command, args []string) error { + return deleteKey(keyDeleteOption) + } + + return cmd +} + +func deleteKey(keyDeleteOption keyDeleteOptions) error { + log := logf.Log + vpcClient, err := vpc.NewV1Client(options.GlobalOptions.VPCRegion) + if err != nil { + return err + } + + listKeysOptions := &vpcv1.ListKeysOptions{} + pager, err := vpcClient.NewKeysPager(listKeysOptions) + if err != nil { + return err + } + + var allResults []vpcv1.Key + for pager.HasNext() { + nextPage, err := pager.GetNext() + if err != nil { + return err + } + allResults = append(allResults, nextPage...) + } + + var keyID string + for _, key := range allResults { + if *key.Name == keyDeleteOption.name { + keyID = *key.ID + break + } + } + + if keyID == "" { + return fmt.Errorf("specified key %s could not be found", keyDeleteOption.name) + } + + options := &vpcv1.DeleteKeyOptions{} + options.SetID(keyID) + + if _, err := vpcClient.DeleteKey(options); err != nil { + return err + } + log.Info("SSH Key deleted successfully,", "key-name", keyDeleteOption.name) + return nil +} diff --git a/cmd/capibmadm/cmd/vpc/key/key.go b/cmd/capibmadm/cmd/vpc/key/key.go index 0c66b1da7..0e0db33e5 100644 --- a/cmd/capibmadm/cmd/vpc/key/key.go +++ b/cmd/capibmadm/cmd/vpc/key/key.go @@ -29,6 +29,7 @@ func Commands() *cobra.Command { } cmd.AddCommand(ListCommand()) - + cmd.AddCommand(CreateCommand()) + cmd.AddCommand(DeleteCommand()) return cmd } diff --git a/docs/book/src/topics/capibmadm/vpc/index.md b/docs/book/src/topics/capibmadm/vpc/index.md index d6a85385a..cd228f94d 100644 --- a/docs/book/src/topics/capibmadm/vpc/index.md +++ b/docs/book/src/topics/capibmadm/vpc/index.md @@ -2,7 +2,11 @@ ## 1. VPC commands -- [image](./image.md) - - [list](/topics/capibmadm/vpc/image.html#1-capibmadm-vpc-image-list) + - [key](./key.md) - [list](/topics/capibmadm/vpc/key.html#1-capibmadm-vpc-key-list) + - [create](/topics/capibmadm/vpc/key.html#2-capibmadm-vpc-key-create) + - [delete](/topics/capibmadm/vpc/key.html#3-capibmadm-vpc-key-delete) + +- [image](./image.md) + - [list](/topics/capibmadm/vpc/image.html#1-capibmadm-vpc-image-list) diff --git a/docs/book/src/topics/capibmadm/vpc/key.md b/docs/book/src/topics/capibmadm/vpc/key.md index 4459b8eec..8787d90f7 100644 --- a/docs/book/src/topics/capibmadm/vpc/key.md +++ b/docs/book/src/topics/capibmadm/vpc/key.md @@ -17,4 +17,56 @@ IBMCLOUD_API_KEY: IBM Cloud API key. ```shell export IBMCLOUD_API_KEY= capibmadm vpc key list --region --resource-group-name -``` \ No newline at end of file +``` + + ### 2. capibmadm vpc key create + + #### Usage: + Create a key in the VPC environment. + + #### Environmental Variable: + IBMCLOUD_API_KEY: IBM Cloud API key. + + #### Arguments: + + --name: The name of the key. + + --resource-group-name: VPC resource group name. + + --region: VPC region. + + Either of the arguments need to be provided: + + --public-key: Public key string within a double quotation marks. For example, "ssh-rsa AAA... ". + + --key-path: The absolute path to the SSH key file. + + + #### Example: + ```shell + export IBMCLOUD_API_KEY= + + capibmadm vpc key create --name --region --public-key "" + + capibmadm vpc key create --name --region --key-path + ``` + + ### 3. capibmadm vpc key delete + + #### Usage: + Delete a key in the VPC environment. + + #### Environmental Variable: + IBMCLOUD_API_KEY: IBM Cloud API key. + + #### Arguments: + + --name: The name of the key. + + --region: VPC region. + + #### Example: + ```shell + export IBMCLOUD_API_KEY= + capibmadm vpc key delete --name --region + ```