Skip to content

Commit 5eff1b0

Browse files
Add prerequisite client and util funcs for capibmadm cli (#1074)
* Add prereq client and util funcs for capibmadm cli * Add context cancel support
1 parent 16cf3d1 commit 5eff1b0

File tree

9 files changed

+379
-3
lines changed

9 files changed

+379
-3
lines changed

cmd/capibmadm/clients/iam/iam.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package iam contains, client to create iam authenticator.
18+
package iam
19+
20+
import (
21+
"github.com/IBM/go-sdk-core/v5/core"
22+
23+
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/options"
24+
)
25+
26+
// GetIAMAuth creates core Authenticator from API key provided.
27+
func GetIAMAuth() *core.IamAuthenticator {
28+
return &core.IamAuthenticator{
29+
ApiKey: options.GlobalOptions.IBMCloudAPIKey,
30+
}
31+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package platformservices contains client functions for platform services.
18+
package platformservices
19+
20+
import (
21+
"github.com/IBM/platform-services-go-sdk/iamidentityv1"
22+
"github.com/IBM/platform-services-go-sdk/resourcemanagerv2"
23+
24+
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/iam"
25+
)
26+
27+
// NewResourceManagerV2Client creates new resource manager client.
28+
func NewResourceManagerV2Client() (*resourcemanagerv2.ResourceManagerV2, error) {
29+
return resourcemanagerv2.NewResourceManagerV2(&resourcemanagerv2.ResourceManagerV2Options{
30+
Authenticator: iam.GetIAMAuth(),
31+
URL: resourcemanagerv2.DefaultServiceURL,
32+
})
33+
}
34+
35+
// NewIAMIdentityClient creates iam identity client.
36+
func NewIAMIdentityClient() (*iamidentityv1.IamIdentityV1, error) {
37+
return iamidentityv1.NewIamIdentityV1(&iamidentityv1.IamIdentityV1Options{
38+
Authenticator: iam.GetIAMAuth(),
39+
URL: iamidentityv1.DefaultServiceURL,
40+
})
41+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package powervs contains powervs client functions.
18+
package powervs
19+
20+
import (
21+
"fmt"
22+
23+
"github.com/IBM-Cloud/power-go-client/ibmpisession"
24+
25+
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/iam"
26+
)
27+
28+
// NewPISession creates new powervs client.
29+
// To-Do: Need to handle custom endpoint URL if user wants to use staging env.
30+
func NewPISession(accountID string, region string, zone string, debug bool) (*ibmpisession.IBMPISession, error) {
31+
return ibmpisession.NewIBMPISession(&ibmpisession.IBMPIOptions{Authenticator: iam.GetIAMAuth(),
32+
Debug: debug,
33+
URL: fmt.Sprintf("https://%s.power-iaas.cloud.ibm.com", region),
34+
UserAccount: accountID,
35+
Zone: zone})
36+
}

cmd/capibmadm/clients/vpc/client.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package vpc contains vpc client functions.
18+
package vpc
19+
20+
import (
21+
"github.com/IBM/vpc-go-sdk/vpcv1"
22+
23+
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/iam"
24+
)
25+
26+
// NewV1Client creates new vpcv1 client.
27+
// To-Do: Need to handle custom endpoint URL if user wants to use staging env.
28+
func NewV1Client(region string) (*vpcv1.VpcV1, error) {
29+
svcEndpoint := "https://" + region + ".iaas.cloud.ibm.com/v1"
30+
31+
return vpcv1.NewVpcV1(&vpcv1.VpcV1Options{
32+
ServiceName: "vpcs",
33+
Authenticator: iam.GetIAMAuth(),
34+
URL: svcEndpoint,
35+
})
36+
}

cmd/capibmadm/cmd/root.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ limitations under the License.
1717
package cmd
1818

1919
import (
20+
"context"
2021
"flag"
2122
"fmt"
2223
"os"
24+
"os/signal"
25+
"syscall"
2326

2427
"github.com/spf13/cobra"
2528

@@ -56,8 +59,20 @@ func rootCommand() *cobra.Command {
5659

5760
// Execute executes the root command.
5861
func Execute() {
59-
if err := rootCommand().Execute(); err != nil {
60-
fmt.Fprintln(os.Stderr, err)
62+
cmd := rootCommand()
63+
64+
ctx, cancel := context.WithCancel(context.Background())
65+
66+
sigs := make(chan os.Signal, 1)
67+
signal.Notify(sigs, syscall.SIGINT)
68+
go func() {
69+
<-sigs
70+
fmt.Fprintln(os.Stderr, "\nAborted...")
71+
cancel()
72+
}()
73+
74+
if err := cmd.ExecuteContext(ctx); err != nil {
75+
fmt.Fprintf(os.Stderr, "%v\n", err)
6176
os.Exit(1)
6277
}
6378
}

cmd/capibmadm/utils/printer.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package utils
18+
19+
import (
20+
"encoding/json"
21+
"errors"
22+
"fmt"
23+
"io"
24+
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/apimachinery/pkg/runtime"
27+
"k8s.io/cli-runtime/pkg/printers"
28+
)
29+
30+
// PrinterType is a type declaration for a printer type.
31+
type PrinterType string
32+
33+
var (
34+
// PrinterTypeTable is a table printer type.
35+
PrinterTypeTable = PrinterType("table")
36+
// PrinterTypeJSON is a json printer type.
37+
PrinterTypeJSON = PrinterType("json")
38+
)
39+
40+
var (
41+
// ErrUnknowPrinterType is an error if a printer type isn't known.
42+
ErrUnknowPrinterType = errors.New("unknown printer type")
43+
// ErrTableRequired is an error if the object being printed
44+
// isn't a metav1.Table.
45+
ErrTableRequired = errors.New("metav1.Table is required")
46+
)
47+
48+
// Printer is an interface for a printer.
49+
type Printer interface {
50+
// Print is a method to print an object
51+
Print(in interface{}) error
52+
}
53+
54+
// NewPrinter creates a new printer.
55+
func NewPrinter(printerType string, writer io.Writer) (Printer, error) {
56+
switch printerType {
57+
case string(PrinterTypeTable):
58+
return &tablePrinter{writer: writer}, nil
59+
case string(PrinterTypeJSON):
60+
return &jsonPrinter{writer: writer}, nil
61+
default:
62+
return nil, ErrUnknowPrinterType
63+
}
64+
}
65+
66+
type tablePrinter struct {
67+
writer io.Writer
68+
}
69+
70+
func (p *tablePrinter) Print(in interface{}) error {
71+
table, ok := in.(*metav1.Table)
72+
if !ok {
73+
return ErrTableRequired
74+
}
75+
76+
options := printers.PrintOptions{}
77+
tablePrinter := printers.NewTablePrinter(options)
78+
scheme := runtime.NewScheme()
79+
printer, err := printers.NewTypeSetter(scheme).WrapToPrinter(tablePrinter, nil)
80+
if err != nil {
81+
return err
82+
}
83+
84+
return printer.PrintObj(table, p.writer)
85+
}
86+
87+
type jsonPrinter struct {
88+
writer io.Writer
89+
}
90+
91+
func (p *jsonPrinter) Print(in interface{}) error {
92+
data, err := json.MarshalIndent(in, "", " ")
93+
if err != nil {
94+
return fmt.Errorf("marshalling object as json: %w", err)
95+
}
96+
_, err = p.writer.Write(data)
97+
return err
98+
}

cmd/capibmadm/utils/utils.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package utils contains utility and printer functions for cli.
18+
package utils
19+
20+
import (
21+
"context"
22+
"fmt"
23+
24+
"github.com/go-openapi/strfmt"
25+
26+
"github.com/IBM/go-sdk-core/v5/core"
27+
"github.com/IBM/platform-services-go-sdk/iamidentityv1"
28+
"github.com/IBM/platform-services-go-sdk/resourcemanagerv2"
29+
30+
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/platformservices"
31+
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/options"
32+
)
33+
34+
// GetAccountID returns IBM cloud account ID of API key used.
35+
func GetAccountID(ctx context.Context, auth *core.IamAuthenticator) (string, error) {
36+
iamv1, err := platformservices.NewIAMIdentityClient()
37+
if err != nil {
38+
return "", err
39+
}
40+
41+
apiKeyDetailsOpt := iamidentityv1.GetAPIKeysDetailsOptions{IamAPIKey: &options.GlobalOptions.IBMCloudAPIKey}
42+
apiKey, _, err := iamv1.GetAPIKeysDetailsWithContext(ctx, &apiKeyDetailsOpt)
43+
if err != nil {
44+
return "", err
45+
}
46+
if apiKey == nil {
47+
return "", fmt.Errorf("could not retrieve account id")
48+
}
49+
50+
return *apiKey.AccountID, nil
51+
}
52+
53+
// GetResourceGroupID returns ID of given resource group name.
54+
func GetResourceGroupID(ctx context.Context, resourceGroup string, accountID string) (string, error) {
55+
rmv2, err := platformservices.NewResourceManagerV2Client()
56+
57+
if err != nil {
58+
return "", err
59+
}
60+
61+
if rmv2 == nil {
62+
return "", fmt.Errorf("unable to get resource controller")
63+
}
64+
65+
rmv2ListResourceGroupOpt := resourcemanagerv2.ListResourceGroupsOptions{Name: &resourceGroup, AccountID: &accountID}
66+
resourceGroupListResult, _, err := rmv2.ListResourceGroupsWithContext(ctx, &rmv2ListResourceGroupOpt)
67+
if err != nil {
68+
return "", err
69+
}
70+
71+
if resourceGroupListResult != nil && len(resourceGroupListResult.Resources) > 0 {
72+
rg := resourceGroupListResult.Resources[0]
73+
resourceGroupID := *rg.ID
74+
return resourceGroupID, nil
75+
}
76+
77+
err = fmt.Errorf("could not retrieve resource group id for %s", resourceGroup)
78+
return "", err
79+
}
80+
81+
// DereferencePointer dereferences pointer.
82+
func DereferencePointer(value interface{}) interface{} {
83+
switch v := value.(type) {
84+
case *string:
85+
if v != nil {
86+
return *v
87+
}
88+
return ""
89+
case *int, *int8, *int16, *int32, *int64:
90+
i := value.(*int64)
91+
if i != nil {
92+
return *i
93+
}
94+
return 0
95+
case *strfmt.DateTime:
96+
if v != nil {
97+
return *v
98+
}
99+
return strfmt.DateTime{}
100+
case *bool:
101+
if v != nil {
102+
return *v
103+
}
104+
return false
105+
case *float32, *float64:
106+
f := value.(*float64)
107+
if f != nil {
108+
return *f
109+
}
110+
return 0
111+
}
112+
return nil
113+
}

0 commit comments

Comments
 (0)