Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add crawler API and controller #95

Merged
merged 7 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
26 changes: 26 additions & 0 deletions CONTIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,29 @@ These rules/guidelines are meant to help keep a well defined style for accomplis
2. Optional embedded struct fields, and sometimes string/bool/int fields, with no defaults should use pointers. A general rule of thumb is to consider how you want to handle the configuration logic surrounding that field in the controller code. If the field may not be configured commonly then it may be convenient to do a simple `if x == nil` check to keep it blank in the resulting K8s Kind struct. Optional embedded struct fields are especially convenient to just check against nil.
3. A required field should usually specify a default, and that default should usually try to match a default configuration from chia-blockchain, or one that is especially advantageous to running in kubernetes. Some required fields don't need defaults, like the one for a chia mnemonic.
4. Fields that are autogenerated by kubebuilder should be left as-is and these rules do not apply to them.

## Adding a new API and Controller

You will need Golang, Make, and Kubebuilder CLI. See the [Kubebuilder book](https://book.kubebuilder.io/quick-start) for installing the CLI.

You can then create a new API and controller with `kubebuilder create api --group k8s.chia.net --version v1 --kind ChiaSomething`
Change ChiaSomething to your desired Kind; for a harvester, the name is ChiaHarvester.
When you enter the command, it will ask you if you want to create the resource and the controller, type `y` for both.

Kubebuilder scaffolds a lot of files for us, but its defaults are a bit undesirable. There are multiple edits we will make besides implementing the API and controller logic that are described below:

- The first thing you will need to change is in `config/crd/kustomization.yaml`. In the `resources` block of this file, edit the created resource name, it will look something like `- bases/k8s.chia.net.k8s.chia.net_chiasomething.yaml`, which should be changed to `- bases/k8s.chia.net_chiasomething.yaml`

- In `config/default/kustomization.yaml` in the `resources` block, make sure the line `- ../crd` is commented. Kubebuilder CLI will have uncommented it.

- In `config/rbac` there will be multiple files that get made which will contain the same redundant `k8s.chia.net.k8s.chia.net` text. Change all occurences to `k8s.chia.net`.

- In `config/samples` the name of the sample kubebuilder created should be changed to the Kind of the controller resource, such as `chiasomething.yaml`.

- In `api/v1` edit the API types to match the needs of the API. Lean on the other API types for examples.

- In `internal/metrics` make some new metric counters for the new Kind you created.

- In `internal/controller` two files were created for the controller and controller's test. I usually find it simpler to delete these, and copy one of the existing controller directories and start editing that one. All of the existing controllers are contained in their own packages in this directory, a pretty simple example would be ChiaWallet. Each of their tests are just contained in the `internal/controller` directory though.

- In `cmd/main.go` we previously moved the reconciler function for the controller to its own directory, so we need to change where the reconciler function is here.
9 changes: 9 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,13 @@ resources:
kind: ChiaIntroducer
path: github.com/chia-network/chia-operator/api/v1
version: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: k8s.chia.net
group: k8s.chia.net
kind: ChiaCrawler
path: github.com/chia-network/chia-operator/api/v1
version: v1
version: "3"
63 changes: 63 additions & 0 deletions api/v1/chiacrawler_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Copyright 2024 Chia Network Inc.
*/

package v1

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

// ChiaCrawlerSpec defines the desired state of ChiaCrawler
type ChiaCrawlerSpec struct {
CommonSpec `json:",inline"`

// ChiaConfig defines the configuration options available to Chia component containers
ChiaConfig ChiaCrawlerSpecChia `json:"chia"`

// Strategy describes how to replace existing pods with new ones.
// +optional
Strategy *appsv1.DeploymentStrategy `json:"strategy,omitempty"`
}

// ChiaCrawlerSpecChia defines the desired state of Chia component configuration
type ChiaCrawlerSpecChia struct {
CommonSpecChia `json:",inline"`

// CASecretName is the name of the secret that contains the CA crt and key. Not required for seeders.
// +optional
CASecretName *string `json:"caSecretName"`
}

// ChiaCrawlerStatus defines the observed state of ChiaCrawler
type ChiaCrawlerStatus struct {
// Ready says whether the chia component is ready deployed
// +kubebuilder:default=false
Ready bool `json:"ready,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// ChiaCrawler is the Schema for the chiacrawlers API
type ChiaCrawler struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ChiaCrawlerSpec `json:"spec,omitempty"`
Status ChiaCrawlerStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// ChiaCrawlerList contains a list of ChiaCrawler
type ChiaCrawlerList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ChiaCrawler `json:"items"`
}

func init() {
SchemeBuilder.Register(&ChiaCrawler{}, &ChiaCrawlerList{})
}
99 changes: 99 additions & 0 deletions api/v1/chiacrawler_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
Copyright 2023 Chia Network Inc.
*/

package v1

import (
"testing"

"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)

func TestUnmarshalChiaCrawler(t *testing.T) {
yamlData := []byte(`
apiVersion: k8s.chia.net/v1
kind: ChiaCrawler
metadata:
labels:
app.kubernetes.io/name: chiacrawler
app.kubernetes.io/instance: chiacrawler-sample
app.kubernetes.io/part-of: chia-operator
app.kubernetes.io/created-by: chia-operator
name: chiacrawler-sample
spec:
chia:
caSecretName: chiaca-secret
testnet: true
network: testnet68419
networkPort: 8080
introducerAddress: introducer.svc.cluster.local
dnsIntroducerAddress: dns-introducer.svc.cluster.local
timezone: "UTC"
logLevel: "INFO"
chiaExporter:
enabled: true
serviceLabels:
network: testnet
`)

var (
testnet = true
timezone = "UTC"
logLevel = "INFO"
network = "testnet68419"
networkPort uint16 = 8080
introducerAddress = "introducer.svc.cluster.local"
dnsIntroducerAddress = "dns-introducer.svc.cluster.local"
caSecret = "chiaca-secret"
)
expect := ChiaCrawler{
TypeMeta: metav1.TypeMeta{
APIVersion: "k8s.chia.net/v1",
Kind: "ChiaCrawler",
},
ObjectMeta: metav1.ObjectMeta{
Name: "chiacrawler-sample",
Labels: map[string]string{
"app.kubernetes.io/name": "chiacrawler",
"app.kubernetes.io/instance": "chiacrawler-sample",
"app.kubernetes.io/part-of": "chia-operator",
"app.kubernetes.io/created-by": "chia-operator",
},
},
Spec: ChiaCrawlerSpec{
ChiaConfig: ChiaCrawlerSpecChia{
CommonSpecChia: CommonSpecChia{
Testnet: &testnet,
Network: &network,
NetworkPort: &networkPort,
IntroducerAddress: &introducerAddress,
DNSIntroducerAddress: &dnsIntroducerAddress,
Timezone: &timezone,
LogLevel: &logLevel,
},
CASecretName: &caSecret,
},
CommonSpec: CommonSpec{
ChiaExporterConfig: SpecChiaExporter{
Enabled: true,
},
},
},
}

var actual ChiaCrawler
err := yaml.Unmarshal(yamlData, &actual)
if err != nil {
t.Errorf("Error unmarshaling yaml: %v", err)
return
}

diff := cmp.Diff(actual, expect)
if diff != "" {
t.Errorf("Unmarshaled struct does not match the expected struct. Actual: %+v\nExpected: %+v\nDiff: %s", actual, expect, diff)
return
}
}
117 changes: 117 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ package main

import (
"flag"
"github.com/chia-network/chia-operator/internal/controller/chiaintroducer"
"os"

"github.com/chia-network/chia-operator/internal/controller/chiaintroducer"

_ "k8s.io/client-go/plugin/pkg/client/auth"

"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -21,6 +22,7 @@ import (

k8schianetv1 "github.com/chia-network/chia-operator/api/v1"
"github.com/chia-network/chia-operator/internal/controller/chiaca"
"github.com/chia-network/chia-operator/internal/controller/chiacrawler"
"github.com/chia-network/chia-operator/internal/controller/chiafarmer"
"github.com/chia-network/chia-operator/internal/controller/chiaharvester"
"github.com/chia-network/chia-operator/internal/controller/chianode"
Expand Down Expand Up @@ -147,6 +149,13 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "ChiaIntroducer")
os.Exit(1)
}
if err = (&chiacrawler.ChiaCrawlerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ChiaCrawler")
os.Exit(1)
}
//+kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand Down
Loading
Loading