Go言語からArgoCDのApplication CustomResourceを作成する例

# argocd v1alpha1.Application構造体を生成する

まず、Application構造体を生成します。SourceやDestinationなどに指定するパラメタはYAMLでApplicationを書いているときと同じです。

```golang
	app := &v1alpha1.Application{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "myapp",
			Namespace: "argocd",
		},
		Spec: v1alpha1.ApplicationSpec{
			Source: v1alpha1.ApplicationSource{
				RepoURL:        "",
				Path:           "",
				TargetRevision: "",
				Helm:           nil,
				Kustomize:      nil,
				Ksonnet:        nil,
				Directory:      nil,
				Plugin:         nil,
				Chart:          "",
			},
			Destination: v1alpha1.ApplicationDestination{
				Server:    "",
				Namespace: "",
				Name:      "",
			},
			Project:              "default",
			SyncPolicy:           nil,
			IgnoreDifferences:    nil,
			Info:                 nil,
			RevisionHistoryLimit: nil,
		},
	}
```

次にargocdのclientsetを使ってカスタムリソースを実際に作成します。

```golang
clientset.ArgoprojV1alpha1()
         .Applications("default")
         .Create(context.TODO(), app, metav1.CreateOptions{})
```

# コード全文

```golang
package main

import (
	"context"
	"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
	"os"
	"path/filepath"

	argocdclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)

var config *rest.Config

type Client struct {
	clientset    *kubernetes.Clientset
	argocdClient argocdclientset.Interface
}

func exists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}

func NewClient() (client *Client, err error) {
	if config == nil {
		var kubeconfig string

		kubeconfig, ok := os.LookupEnv("KUBECONFIG")
		if !ok {
			pathToConfig := filepath.Join(homedir.HomeDir(), ".kube", "config")

			if exists(pathToConfig) {
				kubeconfig = pathToConfig
				config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
			} else {
				config, err = rest.InClusterConfig()
			}
			if err != nil {
				return nil, err
			}
		}
	}

	// create the clientset
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	argocdclientset, err := argocdclientset.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return &Client{
		clientset:    clientset,
		argocdClient: argocdclientset,
	}, nil
}

func (c *Client) CreateNamespace(namespace string) (err error) {
	_, err = c.clientset.CoreV1().Namespaces().Create(context.Background(), &v1.Namespace{
		ObjectMeta: metav1.ObjectMeta{
			Name: namespace,
		},
	}, metav1.CreateOptions{})
	if err != nil {
		return err
	}
	return nil
}

func main() {
	c, err := NewClient()
	if err != nil {
		panic(err)
	}

	app := &v1alpha1.Application{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "myapp",
			Namespace: "argocd",
		},
		Spec: v1alpha1.ApplicationSpec{
			Source: v1alpha1.ApplicationSource{
				RepoURL:        "",
				Path:           "",
				TargetRevision: "",
				Helm:           nil,
				Kustomize:      nil,
				Ksonnet:        nil,
				Directory:      nil,
				Plugin:         nil,
				Chart:          "",
			},
			Destination: v1alpha1.ApplicationDestination{
				Server:    "",
				Namespace: "",
				Name:      "",
			},
			Project:              "default",
			SyncPolicy:           nil,
			IgnoreDifferences:    nil,
			Info:                 nil,
			RevisionHistoryLimit: nil,
		},
	}

	_, err = c.argocdClient.ArgoprojV1alpha1().Applications("default").Create(context.TODO(), app, metav1.CreateOptions{})
	if err != nil {
		panic(err)
	}
}
```

このコードはきっと動きますが、プロダクション用ではない例となるコードなので参考程度に参照ください。


# 参照

- [argoproj/argo-cd: Declarative continuous deployment for Kubernetes.](https://github.com/argoproj/argo-cd)
- [v1alpha1 package - github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1 - pkg.go.dev](https://pkg.go.dev/github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1)
- [kubernetes/client-go: Go client for Kubernetes.](https://github.com/kubernetes/client-go)