Skip to content

Commit

Permalink
Add operator go client (#731)
Browse files Browse the repository at this point in the history
  • Loading branch information
bstadlbauer committed Jun 23, 2023
1 parent 97dfbbc commit b4d9cc4
Show file tree
Hide file tree
Showing 64 changed files with 5,246 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
dask_kubernetes/_version.py export-subst
* text=auto

dask_kubernetes/operator/go_client/pkg/apis/kubernetes.dask.org/v1/zz_generated.deepcopy.go linguist-generated=true
dask_kubernetes/operator/go_client/pkg/client/** linguist-generated=true
29 changes: 29 additions & 0 deletions .github/workflows/update-go-package-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# As we're using CalVer, we need to update the major version of the go package every year
# More info in this discussion: https://github.com/dask/dask-kubernetes/pull/731#discussion_r1226569925
name: "Update go package version"

on:
schedule:
- cron: "0 0 2 1 *" # 00:00 UTC on the 2nd of January every year

jobs:
update-major-go-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Update go package version
run: |
PAST_YEAR=$(date -d "last year" '+%Y')
CURRENT_YEAR=$(date '+%Y')
sed -i "s/v${PAST_YEAR}/v${CURRENT_YEAR}/g" go.mod
sed -i "s/v${PAST_YEAR}/v${CURRENT_YEAR}/g" dask_kubernetes/operator/go_client/hack/regenerate-code.sh
sed -i "s/v${PAST_YEAR}/v${CURRENT_YEAR}/g" dask_kubernetes/operator/go_client/pkg/apis/kubernetes.dask.org/v1/register.go
./dask_kubernetes/operator/go_client/hack/regenerate-code.sh
- uses: peter-evans/create-pull-request@v4
with:
commit-message: "Update major go package version"
title: "Update major go package version"
body: "Update major go package version"
branch: "update-go-package-version"
branch-suffix: "timestamp"
delete-branch: true
29 changes: 29 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,32 @@ repos:
language: script
types: [yaml]
pass_filenames: true
- id: regenerate-go-code
name: regenerate-go-code
entry: dask_kubernetes/operator/go_client/hack/regenerate-code.sh
language: script
files: |
(?x)^(
go\.mod
|go\.sum
|dask_kubernetes/operator/go_client/pkg/apis/.*\.go
)$
exclude: ^dask_kubernetes/operator/go_client/pkg/apis/.*zz_generated.*\.go$
pass_filenames: false
- id: lint-go-code
name: lint-go-code
entry: dask_kubernetes/operator/go_client/hack/lint.sh
language: script
files: ^dask_kubernetes/operator/go_client/.*\.go$
pass_filenames: false
- id: build-go-code
name: build-go-code
entry: golang:1.19.10-bookworm bash -c 'GOCACHE=/src/.cache go build ./...'
language: docker_image
files: |
(?x)^(
go\.mod
|go\.sum
|dask_kubernetes/operator/go_client/.*\.go
)$
pass_filenames: false
6 changes: 6 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
* @jacobtomlinson
dask_kubernetes/operator/customresources/ @jacobtomlinson @bstadlbauer

# Go operator
go.mod @jacobtomlinson @bstadlbauer
go.sum @jacobtomlinson @bstadlbauer
dask_kubernetes/operator/go_client/ @jacobtomlinson @bstadlbauer
25 changes: 25 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,28 @@ For general information on how to contribute see https://docs.dask.org/en/latest

For local development, it is often desirable to run the scheduler process on one’s local machine & the workers on minikube.
For more information on setting this up see https://kubernetes.dask.org/en/latest/testing.html.


### Dask operator - `go` client
We're also releasing a `go` client for the dask operator. In case you make changes to the custom resource definitions in `dask_kubernetes/operator/customresources/`, please also check whether this has an
effect on any of the types in `dask_kubernetes/operator/go_client/pkg/apis/kubernetes.dask.org/v1/types.go` and adapt them accordingly.

This being a Python repository, with a few (mostly auto-generated) `go` files, we've decided on an approach of linting an and code-generating `go` files within Docker. So in case you want to update the `go` files, no local `go` installation is required, but you will need to have `docker` ([docs](https://www.docker.com/)) installed.

#### Linting
In case you would like to lint the `go` files, run
```bash
./dask_kubernetes/operator/go_client/hack/lint.sh
```
Linting will also happen automatically upon commit and on CI, using `pre-commit`.

#### Code generation
In case you have changed the custom resource definitions, please port your changes to `dask_kubernetes/operator/go_client/pkg/apis/kubernetes.dask.org/v1/types.go` and then run

```bash
./dask_kubernetes/operator/go_client/hack/regenerate-code.sh
```
to regenerate all the files. Code-generation will also happen automatically upon commit and on CI, using `pre-commit`.

#### Versioning
`go` is very opinionated when it comes to versioning, especially regarding breaking changes. It's versioning system is designed around [Semantic Versioning](https://semver.org/) which is different from [Calendar Versioning](https://calver.org/) used throughout `dask`. In `go`, each major version is it's own package ([docs](https://go.dev/doc/modules/release-workflow#breaking)), which is why need to increase the version (i.e. the year from CalVer) in `./go.mod` as well as in `./dask_kubernetes/operator/go_client/hack/regenerate-code.sh` yearly for this work.
9 changes: 9 additions & 0 deletions dask_kubernetes/operator/go_client/hack/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM golang:1.19.9

RUN git clone \
--depth=1 \
--branch v0.24.15 \
https://github.com/kubernetes/code-generator.git \
$GOPATH/src/k8s.io/code-generator

RUN touch $HOME/boilerplate.txt
17 changes: 17 additions & 0 deletions dask_kubernetes/operator/go_client/hack/lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash -e

CURRENT_DIR=$(dirname ${BASH_SOURCE})
REPO_DIR=$(realpath "$CURRENT_DIR/../../../..")

docker run \
--rm \
-v "${REPO_DIR}":/app \
-v ~/.cache/golangci-lint/v1.53.2:/root/.cache \
-w /app \
golangci/golangci-lint:v1.53.2 \
golangci-lint \
run -v \
--enable goimports \
--enable gofmt \
--timeout 3m0s \
./...
28 changes: 28 additions & 0 deletions dask_kubernetes/operator/go_client/hack/regenerate-code.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash -e

CURRENT_DIR=$(dirname ${BASH_SOURCE})
REPO_DIR=$(realpath "$CURRENT_DIR/../../../..")
MAJOR_VERSION="v2023"

PROJECT_MODULE="github.com/dask/dask-kubernetes/${MAJOR_VERSION}"
IMAGE_NAME="kubernetes-codegen:latest"

CUSTOM_RESOURCE_NAME="kubernetes.dask.org"
CUSTOM_RESOURCE_VERSION="v1"

echo "Building codegen Docker image..."
docker build -f "${CURRENT_DIR}/Dockerfile" \
-t "${IMAGE_NAME}" \
.

echo "Generating client codes..."
docker run --rm \
-v "${REPO_DIR}:/go/src/${PROJECT_MODULE}" \
-w "/go/src/${PROJECT_MODULE}" \
"${IMAGE_NAME}" \
/go/src/k8s.io/code-generator/generate-groups.sh \
all \
$PROJECT_MODULE/dask_kubernetes/operator/go_client/pkg/client \
$PROJECT_MODULE/dask_kubernetes/operator/go_client/pkg/apis \
$CUSTOM_RESOURCE_NAME:$CUSTOM_RESOURCE_VERSION \
-h /root/boilerplate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// +k8s:deepcopy-gen=package,register

// Package v1 is the v1 version of the API.
// +groupName=kubernetes.dask.org
package v1
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package v1

import (
daskoperator "github.com/dask/dask-kubernetes/v2023/dask_kubernetes/operator/go_client/pkg/apis"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)

const (
Version = "v1"
)

var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)

// SchemeGroupVersion is the group version used to register these objects.
var SchemeGroupVersion = schema.GroupVersion{Group: daskoperator.GroupName, Version: Version}

// Resource takes an unqualified resource and returns a Group-qualified GroupResource.
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

// addKnownTypes adds the set of types defined in this package to the supplied scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(
SchemeGroupVersion,
&DaskCluster{},
&DaskClusterList{},
&DaskWorkerGroup{},
&DaskWorkerGroupList{},
&DaskJob{},
&DaskJobList{},
&DaskAutoscaler{},
&DaskAutoscalerList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package v1

import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type WorkerSpec struct {
Replicas int `json:"replicas"`
Spec v1.PodSpec `json:"spec"`
}

type SchedulerSpec struct {
Spec v1.PodSpec `json:"spec"`
Service v1.ServiceSpec `json:"service"`
}

type DaskClusterSpec struct {
Worker WorkerSpec `json:"worker"`
Scheduler SchedulerSpec `json:"scheduler"`
}

type DaskClusterPhase string

const (
DaskClusterCreated DaskClusterPhase = "Created"
DaskClusterRunning DaskClusterPhase = "Running"
)

type DaskClusterStatus struct {
// The phase the cluster is in right now
Phase DaskClusterPhase `json:"phase,omitempty"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:defaulter-gen=true
type DaskCluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`
Spec DaskClusterSpec `json:"spec"`
Status DaskClusterStatus `json:"status,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DaskClusterList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []DaskCluster `json:"items,omitempty"`
}

type DaskWorkerGroupSpec struct {
Cluster string `json:"cluster"`
Worker WorkerSpec `json:"worker"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:defaulter-gen=true
type DaskWorkerGroup struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`
Spec DaskWorkerGroupSpec `json:"spec"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DaskWorkerGroupList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []DaskWorkerGroup `json:"items,omitempty"`
}

type JobSpec struct {
Spec v1.PodSpec `json:"spec"`
}

type DaskJobSpec struct {
Job JobSpec `json:"job"`
Cluster DaskCluster `json:"cluster"`
}

type JobStatus string

const (
DaskJobCreated JobStatus = "JobCreated"
DaskJobClusterCreated JobStatus = "ClusterCreated"
DaskJobRunning JobStatus = "Running"
DaskJobSuccessful JobStatus = "Successful"
DaskJobFailed JobStatus = "Failed"
)

// DaskJobStatus describes the current status of a Dask Job
type DaskJobStatus struct {
// The name of the cluster the job is executed on
ClusterName string `json:"clusterName,omitempty"`
// The time the job runner pod changed to either Successful or Failing
EndTime metav1.Time `json:"endTime,omitempty"`
// The name of the job-runner pod
JobRunnerPodName string `json:"jobRunnerPodName,omitempty"`
// JobStatus describes the current status of the job
JobStatus JobStatus `json:"jobStatus"`
// Start time records the time the job-runner pod changed into a `running` state
StartTime metav1.Time `json:"startTime"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:defaulter-gen=true
type DaskJob struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`
Spec DaskJobSpec `json:"spec"`
Status DaskJobStatus `json:"status,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DaskJobList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []DaskJob `json:"items,omitempty"`
}

type DaskAutoscalerSpec struct {
// Name of the cluster to associate this autoscaler with
Cluster string `json:"cluster"`
// Minimum number of workers
Minimum string `json:"minimum"`
// Maximum number of workers
Maximum string `json:"maximum"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:defaulter-gen=true
type DaskAutoscaler struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`
Spec DaskAutoscalerSpec `json:"spec"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DaskAutoscalerList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []DaskAutoscaler `json:"items,omitempty"`
}

0 comments on commit b4d9cc4

Please sign in to comment.