-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial v1alpha2 Workflow controller
Signed-off-by: Chris Doherty <[email protected]>
- Loading branch information
1 parent
0b93839
commit eb5eb09
Showing
40 changed files
with
1,041 additions
and
173 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,8 +20,8 @@ GOPROXY ?= $(shell go env GOPROXY) | |
|
||
# Runnable tools | ||
GO ?= go | ||
BUF := $(GO) run github.com/bufbuild/buf/cmd/buf@v1.11 | ||
CONTROLLER_GEN := $(GO) run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11 | ||
BUF := $(GO) run github.com/bufbuild/buf/cmd/buf@v1.29 | ||
CONTROLLER_GEN := $(GO) run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14 | ||
GOFUMPT := $(GO) run mvdan.cc/[email protected] | ||
KUSTOMIZE := $(GO) run sigs.k8s.io/kustomize/kustomize/[email protected] | ||
SETUP_ENVTEST := $(GO) run sigs.k8s.io/controller-runtime/tools/[email protected] | ||
|
@@ -39,7 +39,7 @@ help: ## Print this help | |
@echo | ||
@echo Individual binaries can be built with their name. For example, \`make tink-server\`. | ||
@echo | ||
@echo Individual images can be built with their name appended with -image. For example, | ||
@echo Individual images can be built with their name appended with -image. For example, | ||
@echo \`make tink-server-image\`. | ||
|
||
# Version defines the string injected into binaries that indicates the version of the build. | ||
|
@@ -49,21 +49,21 @@ help: ## Print this help | |
VERSION ?= $(shell git rev-parse --short HEAD) | ||
|
||
# Define all the binaries we build for this project that get packaged into containers. | ||
BINARIES := tink-server tink-agent tink-worker tink-controller virtual-worker | ||
BINARIES := tink-server tink-agent tink-worker tink-controller tink-controller-v1alpha2 virtual-worker | ||
|
||
.PHONY: build | ||
build: $(BINARIES) ## Build all tink binaries. Cross build by setting GOOS and GOARCH. | ||
|
||
# Create targets for all the binaries we build. They can be individually invoked with `make <binary>`. | ||
# For example, `make tink-server`. Callers can cross build by defining the GOOS and GOARCH | ||
# For example, `make tink-server`. Callers can cross build by defining the GOOS and GOARCH | ||
# variables. For example, `GOOS=linux GOARCH=arm64 make tink-server`. | ||
# See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html. | ||
.PHONY: $(BINARIES) | ||
$(BINARIES): | ||
CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GO) build $(LDFLAGS) -o ./bin/$@-$(GOOS)-$(GOARCH) ./cmd/$@ | ||
|
||
# IMAGE_ARGS is resolved when its used in the `%-image` targets. Consequently, the $* automatic | ||
# variable isn't evaluated until the target is called. | ||
# IMAGE_ARGS is resolved when its used in the `%-image` targets. Consequently, the $* automatic | ||
# variable isn't evaluated until the target is called. | ||
# See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html. | ||
IMAGE_ARGS ?= -t $* | ||
|
||
|
@@ -77,8 +77,8 @@ images: $(addsuffix -image,$(BINARIES)) ## Build all tink container images. All | |
# We only build Linux images so we need to force binaries to be built for Linux. Exporting the | ||
# GOOS variable ensures the recipe's binary dependency is built for Linux. | ||
# | ||
# The $$* leverages .SECONDEXPANSION to specify the matched part of the target name as a | ||
# dependency. In doing so, we ensure the binary is built so it can be copied into the image. For | ||
# The $$* leverages .SECONDEXPANSION to specify the matched part of the target name as a | ||
# dependency. In doing so, we ensure the binary is built so it can be copied into the image. For | ||
# example, `make tink-server-image` will depend on `tink-server`. | ||
# See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html. | ||
# See https://www.gnu.org/software/make/manual/html_node/Secondary-Expansion.html. | ||
|
@@ -109,37 +109,41 @@ generate-proto: buf.gen.yaml buf.lock $(shell git ls-files '**/*.proto') _protoc | |
$(GOFUMPT) -w internal/proto/workflow/v2/*.pb.* | ||
|
||
.PHONY: generate | ||
generate: generate-proto generate-go generate-manifests ## Generate code, manifests etc. | ||
generate: ## Generate code, manifests etc. | ||
generate: generate-proto generate-go generate-manifests | ||
|
||
.PHONY: generate-go | ||
generate-go: | ||
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate/boilerplate.generatego.txt" paths="./api/..." | ||
$(GOFUMPT) -w ./api | ||
|
||
.PHONY: generate-manifests | ||
generate-manifests: generate-crds generate-rbacs generate-server-rbacs ## Generate manifests e.g. CRD, RBAC etc. | ||
generate-manifests: ## Generate manifests e.g. CRD, RBAC etc. | ||
generate-manifests: generate-crds generate-rbac | ||
|
||
.PHONY: generate-crds | ||
generate-crds: | ||
$(CONTROLLER_GEN) \ | ||
paths=./api/... \ | ||
crd:crdVersions=v1 \ | ||
rbac:roleName=manager-role \ | ||
output:crd:dir=./config/crd/bases \ | ||
output:webhook:dir=./config/webhook \ | ||
webhook | ||
$(YAMLFMT) ./config/crd/bases/* ./config/webhook/* | ||
|
||
.PHONY: generate-rbacs | ||
generate-rbacs: | ||
.PHONY: | ||
generate-rbac: generate-manager-rbac generate-server-rbac | ||
|
||
.PHONY: generate-controller-rbac | ||
generate-manager-rbac: | ||
$(CONTROLLER_GEN) \ | ||
paths=./internal/controller/... \ | ||
output:rbac:dir=./config/rbac/ \ | ||
paths=./internal/workflow/... \ | ||
output:rbac:dir=./config/manager-rbac/ \ | ||
rbac:roleName=manager-role | ||
$(YAMLFMT) ./config/rbac/* | ||
|
||
.PHONY: generate-server-rbacs | ||
generate-server-rbacs: | ||
.PHONY: generate-server-rbac | ||
generate-server-rbac: | ||
$(CONTROLLER_GEN) \ | ||
paths=./internal/server/... \ | ||
output:rbac:dir=./config/server-rbac \ | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
FROM alpine:3.15 | ||
|
||
ARG TARGETOS | ||
ARG TARGETARCH | ||
|
||
RUN apk add --no-cache --update --upgrade ca-certificates | ||
|
||
COPY bin/tink-controller-v1alpha2-${TARGETOS}-${TARGETARCH} /usr/bin/tink-controller | ||
|
||
ENTRYPOINT ["/usr/bin/tink-controller"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"strings" | ||
|
||
"github.com/go-logr/logr" | ||
"github.com/go-logr/zapr" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
"github.com/spf13/viper" | ||
tinkv1 "github.com/tinkerbell/tink/api/v1alpha2" | ||
"github.com/tinkerbell/tink/internal/workflow" | ||
"go.uber.org/zap" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
amruntimeutil "k8s.io/apimachinery/pkg/util/runtime" | ||
"k8s.io/client-go/tools/clientcmd" | ||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/healthz" | ||
"sigs.k8s.io/controller-runtime/pkg/metrics/server" | ||
) | ||
|
||
// version is set at build time. | ||
var version = "devel" | ||
|
||
// scheme is passed to the manager. | ||
var scheme = runtime.NewScheme() | ||
|
||
func init() { | ||
amruntimeutil.Must(tinkv1.AddToScheme(scheme)) | ||
|
||
//+kubebuilder:scaffold:scheme | ||
} | ||
|
||
type Config struct { | ||
K8sAPI string | ||
Kubeconfig string // only applies to out of cluster | ||
MetricsAddr string | ||
ProbeAddr string | ||
EnableLeaderElection bool | ||
} | ||
|
||
func (c *Config) AddFlags(fs *pflag.FlagSet) { | ||
fs.StringVar(&c.K8sAPI, "kubernetes", "", | ||
"The Kubernetes API URL, used for in-cluster client construction.") | ||
fs.StringVar(&c.Kubeconfig, "kubeconfig", "", "Absolute path to the kubeconfig file") | ||
fs.StringVar(&c.MetricsAddr, "metrics-bind-address", ":8080", | ||
"The address the metric endpoint binds to.") | ||
fs.StringVar(&c.ProbeAddr, "health-probe-bind-address", ":8081", | ||
"The address the probe endpoint binds to.") | ||
fs.BoolVar(&c.EnableLeaderElection, "leader-elect", false, | ||
"Enable leader election for controller manager. "+ | ||
"Enabling this will ensure there is only one active controller manager.") | ||
} | ||
|
||
func main() { | ||
cmd := NewRootCommand() | ||
if err := cmd.Execute(); err != nil { | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func NewRootCommand() *cobra.Command { | ||
var config Config | ||
|
||
zlog, err := zap.NewProduction() | ||
if err != nil { | ||
panic(err) | ||
} | ||
logger := zapr.NewLogger(zlog).WithName("github.com/tinkerbell/tink") | ||
|
||
cmd := &cobra.Command{ | ||
Use: "tink-controller", | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
viper, err := createViper(logger) | ||
if err != nil { | ||
return fmt.Errorf("config init: %w", err) | ||
} | ||
return applyViper(viper, cmd) | ||
}, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
logger.Info("Starting controller version " + version) | ||
|
||
ccfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( | ||
&clientcmd.ClientConfigLoadingRules{ExplicitPath: config.Kubeconfig}, | ||
&clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: config.K8sAPI}}) | ||
|
||
cfg, err := ccfg.ClientConfig() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
namespace, _, err := ccfg.Namespace() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
opts := ctrl.Options{ | ||
Logger: logger, | ||
LeaderElection: config.EnableLeaderElection, | ||
LeaderElectionID: "tink.tinkerbell.org", | ||
LeaderElectionNamespace: namespace, | ||
Metrics: server.Options{ | ||
BindAddress: config.MetricsAddr, | ||
}, | ||
HealthProbeBindAddress: config.ProbeAddr, | ||
Scheme: scheme, | ||
} | ||
|
||
mgr, err := ctrl.NewManager(cfg, opts) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { | ||
return err | ||
} | ||
|
||
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { | ||
return err | ||
} | ||
|
||
if err := workflow.NewReconciler(mgr.GetClient()).SetupWithManager(mgr); err != nil { | ||
return err | ||
} | ||
|
||
return mgr.Start(cmd.Context()) | ||
}, | ||
} | ||
config.AddFlags(cmd.Flags()) | ||
return cmd | ||
} | ||
|
||
func createViper(logger logr.Logger) (*viper.Viper, error) { | ||
v := viper.New() | ||
v.AutomaticEnv() | ||
v.SetConfigName("tink-controller") | ||
v.AddConfigPath("/etc/tinkerbell") | ||
v.AddConfigPath(".") | ||
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) | ||
|
||
// If a config file is found, read it in. | ||
if err := v.ReadInConfig(); err != nil { | ||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok { | ||
return nil, fmt.Errorf("loading config file: %w", err) | ||
} | ||
logger.Info("no config file found") | ||
} else { | ||
logger.Info("loaded config file", "configFile", v.ConfigFileUsed()) | ||
} | ||
|
||
return v, nil | ||
} | ||
|
||
func applyViper(v *viper.Viper, cmd *cobra.Command) error { | ||
errors := []error{} | ||
|
||
cmd.Flags().VisitAll(func(f *pflag.Flag) { | ||
if !f.Changed && v.IsSet(f.Name) { | ||
val := v.Get(f.Name) | ||
if err := cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)); err != nil { | ||
errors = append(errors, err) | ||
return | ||
} | ||
} | ||
}) | ||
|
||
if len(errors) > 0 { | ||
errs := []string{} | ||
for _, err := range errors { | ||
errs = append(errs, err.Error()) | ||
} | ||
return fmt.Errorf(strings.Join(errs, ", ")) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.