Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
278 changes: 153 additions & 125 deletions content/en/flux/gitops-toolkit/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,159 @@ weight: 10
While you can use the GitOps Toolkit APIs in a declarative manner with `kubectl apply`,
we provide client library code for all our toolkit APIs that makes it easier to access them from Go.

```yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: podinfo
namespace: default
spec:
interval: 5m
url: https://github.com/stefanprodan/podinfo
ref:
branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: podinfo
namespace: default
spec:
interval: 10m
targetNamespace: default
sourceRef:
kind: GitRepository
name: podinfo
path: "./kustomize"
prune: true
timeout: 1m
```

## CRUD Example

Here is an example of how to create a Helm release, wait for it to install, then delete it:

```go
package main

import (
"context"
"fmt"
"time"

apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
_ "k8s.io/client-go/plugin/pkg/client/auth"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

helmv2 "github.com/fluxcd/helm-controller/api/v2"
apimeta "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
)

func main() {
// register the GitOps Toolkit schema definitions
scheme := runtime.NewScheme()
_ = sourcev1.AddToScheme(scheme)
_ = helmv2.AddToScheme(scheme)

// init Kubernetes client
kubeClient, err := client.New(ctrl.GetConfigOrDie(), client.Options{Scheme: scheme})
if err != nil {
panic(err)
}

// set a deadline for the Kubernetes API operations
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

// create a Helm repository pointing to Bitnami
helmRepository := &sourcev1.HelmRepository{
ObjectMeta: metav1.ObjectMeta{
Name: "bitnami",
Namespace: "default",
},
Spec: sourcev1.HelmRepositorySpec{
URL: "https://charts.bitnami.com/bitnami",
Interval: metav1.Duration{
Duration: 30 * time.Minute,
},
},
}
if err := kubeClient.Create(ctx, helmRepository); err != nil {
fmt.Println(err)
} else {
fmt.Println("HelmRepository bitnami created")
}

// create a Helm release for nginx
helmRelease := &helmv2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx",
Namespace: "default",
},
Spec: helmv2.HelmReleaseSpec{
ReleaseName: "nginx",
Interval: metav1.Duration{
Duration: 5 * time.Minute,
},
Chart: helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: "nginx",
Version: "8.x",
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: sourcev1.HelmRepositoryKind,
Name: "bitnami",
},
},
},
Values: &apiextensionsv1.JSON{Raw: []byte(`{"service": {"type": "ClusterIP"}}`)},
},
}
if err := kubeClient.Create(ctx, helmRelease); err != nil {
fmt.Println(err)
} else {
fmt.Println("HelmRelease nginx created")
}

// wait for the a Helm release to be reconciled
fmt.Println("Waiting for nginx to be installed")
if err := wait.PollImmediate(2*time.Second, 1*time.Minute,
func() (done bool, err error) {
namespacedName := types.NamespacedName{
Namespace: helmRelease.GetNamespace(),
Name: helmRelease.GetName(),
}
if err := kubeClient.Get(ctx, namespacedName, helmRelease); err != nil {
return false, err
}
return meta.IsStatusConditionTrue(helmRelease.Status.Conditions, apimeta.ReadyCondition), nil
}); err != nil {
fmt.Println(err)
}

// print the reconciliation status
fmt.Println(meta.FindStatusCondition(helmRelease.Status.Conditions, apimeta.ReadyCondition).Message)

// uninstall the release and delete the repository
if err := kubeClient.Delete(ctx, helmRelease); err != nil {
fmt.Println(err)
}
if err := kubeClient.Delete(ctx, helmRepository); err != nil {
fmt.Println(err)
}
fmt.Println("Helm repository and release deleted")
}
```

For an example on how to build a Kubernetes controller that interacts with the GitOps Toolkit APIs see
[source-watcher](source-watcher.md).

## Go Packages

The GitOps Toolkit Go modules and controllers are released by following the [semver](https://semver.org) conventions.
Expand Down Expand Up @@ -138,128 +291,3 @@ API Types
| [ImageRepository](/flux/components/image/imagerepositories/) | v1beta2 |
| [ImagePolicy](/flux/components/image/imagepolicies/) | v1beta2 |
| [ImageUpdateAutomation](/flux/components/image/imageupdateautomations/) | v1beta2 |

## CRUD Example

Here is an example of how to create a Helm release, wait for it to install, then delete it:

```go
package main

import (
"context"
"fmt"
"time"

apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
_ "k8s.io/client-go/plugin/pkg/client/auth"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

helmv2 "github.com/fluxcd/helm-controller/api/v2"
apimeta "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
)

func main() {
// register the GitOps Toolkit schema definitions
scheme := runtime.NewScheme()
_ = sourcev1.AddToScheme(scheme)
_ = helmv2.AddToScheme(scheme)

// init Kubernetes client
kubeClient, err := client.New(ctrl.GetConfigOrDie(), client.Options{Scheme: scheme})
if err != nil {
panic(err)
}

// set a deadline for the Kubernetes API operations
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

// create a Helm repository pointing to Bitnami
helmRepository := &sourcev1.HelmRepository{
ObjectMeta: metav1.ObjectMeta{
Name: "bitnami",
Namespace: "default",
},
Spec: sourcev1.HelmRepositorySpec{
URL: "https://charts.bitnami.com/bitnami",
Interval: metav1.Duration{
Duration: 30 * time.Minute,
},
},
}
if err := kubeClient.Create(ctx, helmRepository); err != nil {
fmt.Println(err)
} else {
fmt.Println("HelmRepository bitnami created")
}

// create a Helm release for nginx
helmRelease := &helmv2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "nginx",
Namespace: "default",
},
Spec: helmv2.HelmReleaseSpec{
ReleaseName: "nginx",
Interval: metav1.Duration{
Duration: 5 * time.Minute,
},
Chart: helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: "nginx",
Version: "8.x",
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: sourcev1.HelmRepositoryKind,
Name: "bitnami",
},
},
},
Values: &apiextensionsv1.JSON{Raw: []byte(`{"service": {"type": "ClusterIP"}}`)},
},
}
if err := kubeClient.Create(ctx, helmRelease); err != nil {
fmt.Println(err)
} else {
fmt.Println("HelmRelease nginx created")
}

// wait for the a Helm release to be reconciled
fmt.Println("Waiting for nginx to be installed")
if err := wait.PollImmediate(2*time.Second, 1*time.Minute,
func() (done bool, err error) {
namespacedName := types.NamespacedName{
Namespace: helmRelease.GetNamespace(),
Name: helmRelease.GetName(),
}
if err := kubeClient.Get(ctx, namespacedName, helmRelease); err != nil {
return false, err
}
return meta.IsStatusConditionTrue(helmRelease.Status.Conditions, apimeta.ReadyCondition), nil
}); err != nil {
fmt.Println(err)
}

// print the reconciliation status
fmt.Println(meta.FindStatusCondition(helmRelease.Status.Conditions, apimeta.ReadyCondition).Message)

// uninstall the release and delete the repository
if err := kubeClient.Delete(ctx, helmRelease); err != nil {
fmt.Println(err)
}
if err := kubeClient.Delete(ctx, helmRepository); err != nil {
fmt.Println(err)
}
fmt.Println("Helm repository and release deleted")
}
```

For an example on how to build a Kubernetes controller that interacts with the GitOps Toolkit APIs see
[source-watcher](source-watcher.md).