Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Commit

Permalink
Discover endpoint and creds via k8s objects
Browse files Browse the repository at this point in the history
  • Loading branch information
nolancon committed Jan 23, 2023
1 parent 0e10504 commit 61e6dc1
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 9 deletions.
19 changes: 13 additions & 6 deletions api_client/apiclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"time"

"github.com/storageos/kubectl-storageos/api_client/openapi"
"github.com/storageos/kubectl-storageos/pkg/consts"
"github.com/storageos/kubectl-storageos/pkg/utils"
"github.com/storageos/kubectl-storageos/pkg/version"
"k8s.io/client-go/rest"
)

// Client wraps the openAPI client providing a collection of useful methods such
Expand All @@ -26,14 +27,15 @@ type client struct {
cacheSessionExpiresAt time.Time
}

func GetAPIClient() (*ClientWithReauth, error) {
func GetAPIClient(restConfig *rest.Config) (*ClientWithReauth, error) {
userAgent := strings.Join([]string{"ondat kubectl plugin", version.PluginVersion}, "/")

// TODO retrieve credentials like before
username, password := "storageos", "storageos"
endpoint, err := utils.GetFirstStorageOSAPIEndpoint(restConfig)
if err != nil {
return nil, err
}

// TODO make endpoints configurable
basicOpenAPIClient, err := openapi.NewOpenAPI([]string{consts.DefaultStorageOSEndpoint}, userAgent)
basicOpenAPIClient, err := openapi.NewOpenAPI([]string{endpoint}, userAgent)
if err != nil {
return nil, err
}
Expand All @@ -43,6 +45,11 @@ func GetAPIClient() (*ClientWithReauth, error) {
OpenAPI: basicOpenAPIClient,
}

username, password, err := utils.GetAPICredentialsFromSecret(restConfig)
if err != nil {
return nil, err
}

// client wrapper adding reauth on first failure
clientWithReauth := NewClientWithReauth(internalClient, username, password)

Expand Down
16 changes: 13 additions & 3 deletions cmd/testapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/spf13/cobra"
apiclient "github.com/storageos/kubectl-storageos/api_client"
"github.com/storageos/kubectl-storageos/pkg/utils"
)

func TestAPICmd() *cobra.Command {
Expand All @@ -21,16 +22,25 @@ func TestAPICmd() *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
// Example of usage of the new api client

cfg, err := utils.NewClientConfig()
if err != nil {
return err
}
// 1 - get client
client, err := apiclient.GetAPIClient()
client, err := apiclient.GetAPIClient(cfg)
if err != nil {
return err
}

// 2 - authenticate
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*2)
defer cancel()
_, _, err = client.Authenticate(ctx, "storageos", "storageos")

username, password, err := utils.GetAPICredentialsFromSecret(cfg)
if err != nil {
return err
}
_, _, err = client.Authenticate(ctx, username, password)
if err != nil {
return err
}
Expand All @@ -51,7 +61,7 @@ func TestAPICmd() *cobra.Command {
fmt.Printf("Got %d volumes back\n", len(vols))

// testing the use of the cached token
_, _, err = client.Authenticate(ctx, "storageos", "storageos")
_, _, err = client.Authenticate(ctx, username, password)
if err != nil {
return err
}
Expand Down
65 changes: 65 additions & 0 deletions pkg/utils/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"context"
"fmt"
"io"
"net/url"
"regexp"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -568,6 +570,69 @@ func GetFirstStorageOSCluster(config *rest.Config) (*operatorapi.StorageOSCluste
return stosCluster, nil
}

func GetFirstStorageOSNodePod(config *rest.Config, namespace string) (*corev1.Pod, error) {
nodePodList, err := ListPods(config, namespace, "app.kubernetes.io/component=control-plane")
if err != nil {
return nil, err
}

if len(nodePodList.Items) == 0 {
return nil, errors.WithStack(fmt.Errorf("no storageos-node pods found"))
}

for _, pod := range nodePodList.Items {
if pod.Status.Phase == corev1.PodRunning {
return &pod, nil
}
}

return nil, errors.WithStack(fmt.Errorf("no storageos-node pod in running phase"))
}

func GetFirstStorageOSAPIEndpoint(config *rest.Config) (string, error) {
stosCluster, err := GetFirstStorageOSCluster(config)
if err != nil {
return "", err
}

// the cluster namespace can be used to fetch the storageos-node pods as they are always the same.
pod, err := GetFirstStorageOSNodePod(config, stosCluster.Namespace)
if err != nil {
return "", err
}

for _, container := range pod.Spec.Containers {
if container.Name == "storageos" {
for _, port := range container.Ports {
if port.Name == "api" {
endpoint, err := url.Parse("http://" + pod.Status.HostIP + ":" + strconv.Itoa(int(port.HostPort)))
if err != nil {
return "", fmt.Errorf("error parsing storageos api endpoint url")
}
return endpoint.String(), nil
}
}
}
}

return "", fmt.Errorf("unable to get storageos api endpoint")
}

func GetAPICredentialsFromSecret(config *rest.Config) (string, string, error) {
stosCluster, err := GetFirstStorageOSCluster(config)
if err != nil {
return "", "", err
}

// the cluster namespace can be used to fetch the secret as they are always the same.
secret, err := GetSecret(config, stosCluster.Spec.SecretRefName, stosCluster.Namespace)
if err != nil {
return "", "", err
}

return string(secret.Data["username"]), string(secret.Data["password"]), nil
}

func storageOSOperatorClient(config *rest.Config) (client.Client, error) {
scheme := runtime.NewScheme()
if err := operatorapi.AddToScheme(scheme); err != nil {
Expand Down

0 comments on commit 61e6dc1

Please # to comment.