Skip to content

Commit

Permalink
Merge pull request #334 from kube-tarian/feature/argocd_cluster
Browse files Browse the repository at this point in the history
Added Argocd cluster apis
  • Loading branch information
vramk23 authored Nov 25, 2023
2 parents 0bdeabe + 4374880 commit 307571d
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 57 deletions.
127 changes: 106 additions & 21 deletions capten/common-pkg/plugins/argocd/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,130 @@ package argocd

import (
"context"
"encoding/base64"
"fmt"
"strings"

"github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/io"
"gopkg.in/yaml.v2"
k8sapi "k8s.io/client-go/tools/clientcmd/api"
)

func (a *ArgoCDClient) CreateCluster(ctx context.Context, clusterReq *Cluster) (*v1alpha1.Cluster, error) {
conn, appClient, err := a.client.NewClusterClient()
const (
CredEntityName = "k8s"
CredIdentifier = "kubeconfig"
)

func parseKubeconfigString(kubeconfigString string) (*k8sapi.Config, error) {
config := &k8sapi.Config{}
err := yaml.Unmarshal([]byte(kubeconfigString), config)
if err != nil {
return nil, err
}
return config, nil
}

func (a *ArgoCDClient) CreateOrUpdateCluster(ctx context.Context, clusterName, kubeconfigData string) error {
kubeConfig, err := parseKubeconfigString(kubeconfigData)
if err != nil {
return err
}

clusterData, ok := kubeConfig.Clusters[clusterName]
if !ok {
return fmt.Errorf("cluster %s not found in kubeconfig", clusterName)
}
caData, err := base64.StdEncoding.DecodeString(string(clusterData.CertificateAuthorityData))
if err != nil {
return err
}

var clusterCAuthInfo *k8sapi.AuthInfo
for _, authInfo := range kubeConfig.AuthInfos {
clusterCAuthInfo = authInfo
break
}

if clusterCAuthInfo == nil {
return fmt.Errorf("auth info not found for cluster")
}

var clientCertData []byte
if len(clusterCAuthInfo.ClientCertificateData) != 0 {
clientCertData, err = base64.StdEncoding.DecodeString(string(clusterCAuthInfo.ClientCertificateData))
if err != nil {
return err
}
}

a.logger.Infof("Cluster create or update request for cluster %s", clusterName)
var clientKeyData []byte
if len(clusterCAuthInfo.ClientKeyData) != 0 {
clientKeyData, err = base64.StdEncoding.DecodeString(string(clusterCAuthInfo.ClientKeyData))
if err != nil {
return err
}
}

conn, appClient, err := a.client.NewClusterClient()
if err != nil {
return fmt.Errorf("failed to create argocd cluster client, %v", err)
}
defer io.Close(conn)

resp, err := appClient.Create(ctx, &cluster.ClusterCreateRequest{
var update bool
_, err = appClient.Create(ctx, &cluster.ClusterCreateRequest{
Cluster: &v1alpha1.Cluster{
Server: clusterReq.Server,
Name: clusterReq.Name,
Server: clusterData.Server,
Name: clusterName,
Config: v1alpha1.ClusterConfig{
Username: clusterReq.Config.Username,
Password: clusterReq.Config.Password,
BearerToken: clusterCAuthInfo.Token,
Username: clusterCAuthInfo.Username,
Password: clusterCAuthInfo.Password,
TLSClientConfig: v1alpha1.TLSClientConfig{
Insecure: clusterReq.Config.Insecure,
ServerName: clusterReq.Config.ServerName,
CertData: clusterReq.Config.CertData,
KeyData: clusterReq.Config.KeyData,
CAData: clusterReq.Config.CAData,
ServerName: clusterData.Server,
CAData: caData,
CertData: clientCertData,
KeyData: clientKeyData,
},
},
ConnectionState: v1alpha1.ConnectionState{
Status: clusterReq.ConnectionState.Status,
Message: clusterReq.ConnectionState.Message,
},
Namespaces: clusterReq.Namespaces,
},
})
if err != nil {
return nil, err
if strings.Contains(err.Error(), "already exists") {
update = true
}
return fmt.Errorf("failed to create cluster %s, %v", clusterName, err)
}
return resp, nil

if update {
_, err := appClient.Update(ctx, &cluster.ClusterUpdateRequest{
Cluster: &v1alpha1.Cluster{
Server: clusterData.Server,
Name: clusterName,
Config: v1alpha1.ClusterConfig{
BearerToken: clusterCAuthInfo.Token,
Username: clusterCAuthInfo.Username,
Password: clusterCAuthInfo.Password,
TLSClientConfig: v1alpha1.TLSClientConfig{
ServerName: clusterData.Server,
CAData: caData,
CertData: clientCertData,
KeyData: clientKeyData,
},
},
},
})
if err != nil {
return fmt.Errorf("failed to update cluster %s, %v", clusterName, err)
}
a.logger.Infof("Cluster %s created", clusterName)
} else {
a.logger.Infof("Cluster %s updated", clusterName)
}
return nil
}

func (a *ArgoCDClient) DeleteCluster(ctx context.Context, clusterURL string) (*cluster.ClusterResponse, error) {
Expand Down Expand Up @@ -69,7 +154,7 @@ func (a *ArgoCDClient) GetCluster(ctx context.Context, clusterURL string) (*v1al
}
defer io.Close(conn)

repository, err := appClient.Get(ctx, &cluster.ClusterQuery{
cluster, err := appClient.Get(ctx, &cluster.ClusterQuery{
Id: &cluster.ClusterID{
Value: clusterURL,
},
Expand All @@ -78,7 +163,7 @@ func (a *ArgoCDClient) GetCluster(ctx context.Context, clusterURL string) (*v1al
return nil, err
}

return repository, nil
return cluster, nil
}

func (a *ArgoCDClient) ListClusters(ctx context.Context) (*v1alpha1.ClusterList, error) {
Expand Down
39 changes: 3 additions & 36 deletions capten/common-pkg/plugins/argocd/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package argocd

import "time"
import (
"time"
)

type Configuration struct {
ServiceURL string `envconfig:"ARGOCD_SERVICE_URL" default:"argo-cd-argocd-server.argo-cd.svc.cluster.local"`
Expand All @@ -26,38 +28,3 @@ type Repository struct {
InsecureIgnoreHostKey bool `json:"InsecureIgnoreHostKey"`
ConnectionState ConnectionState `json:"ConnectionState"`
}

type TLSClientConfig struct {
// Insecure specifies that the server should be accessed without verifying the TLS certificate. For testing only.
Insecure bool `json:"insecure" `
// ServerName is passed to the server for SNI and is used in the client to check server
// certificates against. If ServerName is empty, the hostname used to contact the
// server is used.
ServerName string `json:"serverName,omitempty" `
// CertData holds PEM-encoded bytes (typically read from a client certificate file).
// CertData takes precedence over CertFile
CertData []byte `json:"certData,omitempty" `
// KeyData holds PEM-encoded bytes (typically read from a client certificate key file).
// KeyData takes precedence over KeyFile
KeyData []byte `json:"keyData,omitempty" `
// CAData holds PEM-encoded bytes (typically read from a root certificates bundle).
// CAData takes precedence over CAFile
CAData []byte `json:"caData,omitempty" `
}

type ClusterConfig struct {
// Server requires Basic authentication
Username string `json:"username,omitempty" `
Password string `json:"password,omitempty"`

// TLSClientConfig contains settings to enable transport layer security
TLSClientConfig `json:"tlsClientConfig"`
}

type Cluster struct {
Server string `json:"server"`
Name string `json:"name"`
Config ClusterConfig `json:"config"`
ConnectionState ConnectionState `json:"ConnectionState"`
Namespaces []string `json:"namespaces,omitempty"`
}

0 comments on commit 307571d

Please sign in to comment.