Skip to content

Commit

Permalink
Makefile fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Kidswiss committed Sep 14, 2023
1 parent 57ec555 commit 28a1f63
Show file tree
Hide file tree
Showing 14 changed files with 825 additions and 80 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ dist/
.github/release-notes.md

# Binaries for programs and plugins
appcat
appcat-apiserver
# But don't ignore the appcat APIS!
!apis/appcat

Expand Down
84 changes: 5 additions & 79 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Image URL to use all building/pushing image targets
IMG_TAG ?= latest
GHCR_IMG ?= ghcr.io/vshn/appcat:$(IMG_TAG)
GHCR_IMG ?= ghcr.io/vshn/appcat-apiserver:$(IMG_TAG)
DOCKER_CMD ?= docker

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
Expand All @@ -23,11 +23,11 @@ DOCKER_IMAGE_GOOS = linux
DOCKER_IMAGE_GOARCH = amd64

PROJECT_ROOT_DIR = .
PROJECT_NAME ?= appcat
PROJECT_NAME ?= appcat-apiserver
PROJECT_OWNER ?= vshn

PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
BIN_FILENAME ?= $(PROJECT_DIR)/appcat
BIN_FILENAME ?= $(PROJECT_DIR)/appcat-apiserver

## Stackgres CRDs
STACKGRES_VERSION ?= 1.4.3
Expand Down Expand Up @@ -64,43 +64,12 @@ help: ## Display this help.

.PHONY: generate
generate: export PATH := $(go_bin):$(PATH)
generate: $(protoc_bin) generate-stackgres-crds ## Generate code with controller-gen and protobuf.
generate: $(protoc_bin) ## Generate code with controller-gen and protobuf.
go version
rm -rf apis/generated
go run sigs.k8s.io/controller-tools/cmd/controller-gen paths=./apis/... object crd:crdVersions=v1,allowDangerousTypes=true output:artifacts:config=./apis/generated
go generate ./...
# Because yaml is such a fun and easy specification, we need to hack some things here.
# Depending on the yaml parser implementation the equal sign (=) has special meaning, or not...
# So we make it explicitly a string.
$(sed) -i ':a;N;$$!ba;s/- =\n/- "="\n/g' apis/generated/vshn.appcat.vshn.io_vshnpostgresqls.yaml
rm -rf crds && cp -r apis/generated crds
go run sigs.k8s.io/controller-tools/cmd/controller-gen rbac:roleName=appcat paths="{./apis/...,./pkg/apiserver/...}" output:artifacts:config=config/apiserver
go run sigs.k8s.io/controller-tools/cmd/controller-gen rbac:roleName=appcat-sli-exporter paths="{./pkg/sliexporter/...}" output:artifacts:config=config/sliexporter/rbac
go run k8s.io/code-generator/cmd/go-to-protobuf \
--packages=github.com/vshn/appcat-apiserver/apis/appcat/v1 \
--output-base=./.work/tmp \
--go-header-file=./pkg/apiserver/hack/boilerplate.txt \
--apimachinery-packages='-k8s.io/apimachinery/pkg/util/intstr,-k8s.io/apimachinery/pkg/api/resource,-k8s.io/apimachinery/pkg/runtime/schema,-k8s.io/apimachinery/pkg/runtime,-k8s.io/apimachinery/pkg/apis/meta/v1,-k8s.io/apimachinery/pkg/apis/meta/v1beta1,-k8s.io/api/core/v1,-k8s.io/api/rbac/v1' \
--proto-import=./.work/kubernetes/vendor/ && \
mv ./.work/tmp/github.com/vshn/appcat-apiserver/apis/appcat/v1/generated.pb.go ./apis/appcat/v1/ && \
rm -rf ./.work/tmp

.PHONY: generate-stackgres-crds
generate-stackgres-crds:
curl ${STACKGRES_CRD_URL}/SGDbOps.yaml?inline=false -o apis/stackgres/v1/sgdbops_crd.yaml
yq -i e apis/stackgres/v1/sgdbops.yaml --expression ".components.schemas.SGDbOpsSpec=load(\"apis/stackgres/v1/sgdbops_crd.yaml\").spec.versions[0].schema.openAPIV3Schema.properties.spec"
yq -i e apis/stackgres/v1/sgdbops.yaml --expression ".components.schemas.SGDbOpsStatus=load(\"apis/stackgres/v1/sgdbops_crd.yaml\").spec.versions[0].schema.openAPIV3Schema.properties.status"
go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=v1 -generate=types -o apis/stackgres/v1/sgdbops.gen.go apis/stackgres/v1/sgdbops.yaml
perl -i -0pe 's/\*struct\s\{\n\s\sAdditionalProperties\smap\[string\]string\s`json:"-"`\n\s}/map\[string\]string/gms' apis/stackgres/v1/sgdbops.gen.go

curl ${STACKGRES_CRD_URL}/SGCluster.yaml?inline=false -o apis/stackgres/v1/sgcluster_crd.yaml
yq -i e apis/stackgres/v1/sgcluster.yaml --expression ".components.schemas.SGClusterSpec=load(\"apis/stackgres/v1/sgcluster_crd.yaml\").spec.versions[0].schema.openAPIV3Schema.properties.spec"
yq -i e apis/stackgres/v1/sgcluster.yaml --expression ".components.schemas.SGClusterStatus=load(\"apis/stackgres/v1/sgcluster_crd.yaml\").spec.versions[0].schema.openAPIV3Schema.properties.status"
go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=v1 -generate=types -o apis/stackgres/v1/sgcluster.gen.go apis/stackgres/v1/sgcluster.yaml
perl -i -0pe 's/\*struct\s\{\n\s\sAdditionalProperties\smap\[string\]string\s`json:"-"`\n\s}/map\[string\]string/gms' apis/stackgres/v1/sgcluster.gen.go

go run sigs.k8s.io/controller-tools/cmd/controller-gen object paths=./apis/stackgres/v1/...
rm apis/stackgres/v1/*_crd.yaml
go generate ./...

.PHONY: fmt
fmt: ## Run go fmt against code.
Expand Down Expand Up @@ -148,49 +117,6 @@ kind-load-branch-tag: ## load docker image with current branch tag into kind
docker-push: docker-build ## Push docker image with the manager.
docker push ${GHCR_IMG}

# Generate webhook certificates.
# This is only relevant when debugging.
# Component-appcat installs a proper certificate for this.
.PHONY: webhook-cert
webhook_key = .work/webhook/tls.key
webhook_cert = .work/webhook/tls.crt
webhook-cert: $(webhook_cert) ## Generate webhook certificates for out-of-cluster debugging in an IDE

$(webhook_key):
mkdir -p .work/webhook
ipsan="" && \
if [[ $(webhook_service_name) =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$$ ]]; then \
ipsan=", IP:$(webhook_service_name)"; \
fi; \
openssl req -x509 -newkey rsa:4096 -nodes -keyout $@ --noout -days 3650 -subj "/CN=$(webhook_service_name)" -addext "subjectAltName = DNS:$(webhook_service_name)$$ipsan"

$(webhook_cert): $(webhook_key)
ipsan="" && \
if [[ $(webhook_service_name) =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$$ ]]; then \
ipsan=", IP:$(webhook_service_name)"; \
fi; \
openssl req -x509 -key $(webhook_key) -nodes -out $@ -days 3650 -subj "/CN=$(webhook_service_name)" -addext "subjectAltName = DNS:$(webhook_service_name)$$ipsan"


.PHONY: webhook-debug
webhook_service_name = host.docker.internal

webhook-debug: $(webhook_cert) ## Creates certificates, patches the webhook registrations and applies everything to the given kube cluster
webhook-debug:
kubectl -n syn-appcat scale deployment appcat-controller --replicas 0
cabundle=$$(cat .work/webhook/tls.crt | base64) && \
HOSTIP=$(webhook_service_name) && \
kubectl annotate validatingwebhookconfigurations.admissionregistration.k8s.io appcat-pg-validation cert-manager.io/inject-ca-from- && \
kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io appcat-pg-validation -oyaml | \
yq e "del(.webhooks[0].clientConfig.service) | .webhooks[0].clientConfig.caBundle |= \"$$cabundle\" | .webhooks[0].clientConfig.url |= \"https://$$HOSTIP:9443/validate-vshn-appcat-vshn-io-v1-vshnpostgresql\"" - | \
kubectl apply -f - && \
kubectl annotate validatingwebhookconfigurations.admissionregistration.k8s.io appcat-redis-validation cert-manager.io/inject-ca-from- && \
kubectl annotate validatingwebhookconfigurations.admissionregistration.k8s.io appcat-pg-validation kubectl.kubernetes.io/last-applied-configuration- && \
kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io appcat-redis-validation -oyaml | \
yq e "del(.webhooks[0].clientConfig.service) | .webhooks[0].clientConfig.caBundle |= \"$$cabundle\" | .webhooks[0].clientConfig.url |= \"https://$$HOSTIP:9443/validate-vshn-appcat-vshn-io-v1-vshnredis\"" - | \
kubectl apply -f - && \
kubectl annotate validatingwebhookconfigurations.admissionregistration.k8s.io appcat-redis-validation kubectl.kubernetes.io/last-applied-configuration-

.PHONY: clean
clean:
rm -rf bin/ appcat .work/ docs/node_modules $docs_out_dir .public .cache apiserver.local.config apis/generated default.sock
57 changes: 57 additions & 0 deletions pkg/apiserver/appcat/appcat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package appcat

import (
crossplane "github.com/crossplane/crossplane/apis/apiextensions/v1"
v1 "github.com/vshn/appcat-apiserver/apis/appcat/v1"
"k8s.io/apimachinery/pkg/runtime"
genericregistry "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
restbuilder "sigs.k8s.io/apiserver-runtime/pkg/builder/rest"
"sigs.k8s.io/apiserver-runtime/pkg/util/loopback"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch,resourceNames=extension-apiserver-authentication
// +kubebuilder:rbac:groups="admissionregistration.k8s.io",resources=mutatingwebhookconfigurations;validatingwebhookconfigurations,verbs=get;list;watch
// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch;create;delete;update
// +kubebuilder:rbac:groups="authorization.k8s.io",resources=subjectaccessreviews,verbs=get;list;watch;create;delete;update

// New returns a new storage provider for AppCat
func New() restbuilder.ResourceHandlerProvider {
return func(s *runtime.Scheme, gasdf genericregistry.RESTOptionsGetter) (rest.Storage, error) {
c, err := client.NewWithWatch(loopback.GetLoopbackMasterClientConfig(), client.Options{})
if err != nil {
return nil, err
}
err = v1.AddToScheme(c.Scheme())
if err != nil {
return nil, err
}
err = crossplane.AddToScheme(c.Scheme())
if err != nil {
return nil, err
}
return &appcatStorage{
compositions: &kubeCompositionProvider{
Client: c,
},
}, nil
}
}

type appcatStorage struct {
compositions compositionProvider
}

func (s *appcatStorage) New() runtime.Object {
return &v1.AppCat{}
}

func (s *appcatStorage) Destroy() {}

var _ rest.Scoper = &appcatStorage{}
var _ rest.Storage = &appcatStorage{}

func (s *appcatStorage) NamespaceScoped() bool {
return false
}
92 changes: 92 additions & 0 deletions pkg/apiserver/appcat/appcat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package appcat

import (
"testing"

crossplanev1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
v1 "github.com/vshn/appcat-apiserver/apis/appcat/v1"
"github.com/vshn/appcat-apiserver/test/mocks"
"k8s.io/apiserver/pkg/registry/rest"

"github.com/golang/mock/gomock"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// newMockedAppCatStorage is a mocked instance of AppCatStorage
func newMockedAppCatStorage(t *testing.T, ctrl *gomock.Controller) (rest.StandardStorage, *mocks.MockcompositionProvider) {
t.Helper()
comp := mocks.NewMockcompositionProvider(ctrl)
stor := &appcatStorage{
compositions: comp,
}
return rest.Storage(stor).(rest.StandardStorage), comp
}

// Test AppCat instances
var (
appCatOne = &v1.AppCat{
ObjectMeta: metav1.ObjectMeta{
Name: "one",
},

Details: map[string]string{
"zone": "rma1",
"displayname": "one",
"docs": "https://docs.com",
},

Status: v1.AppCatStatus{
CompositionName: "one",
},
}
compositionOne = &crossplanev1.Composition{
ObjectMeta: metav1.ObjectMeta{
Name: "one",
Labels: map[string]string{
v1.OfferedKey: v1.OfferedValue,
},
Annotations: map[string]string{
v1.PrefixAppCatKey + "/zone": "rma1",
v1.PrefixAppCatKey + "/displayname": "one",
v1.PrefixAppCatKey + "/docs": "https://docs.com",
},
},
}
appCatTwo = &v1.AppCat{
ObjectMeta: metav1.ObjectMeta{
Name: "two",
},

Details: map[string]string{
"zone": "lpg",
"displayname": "two",
"docs": "https://docs.com",
"productDescription": "product desc",
},

Status: v1.AppCatStatus{
CompositionName: "two",
},
}
compositionTwo = &crossplanev1.Composition{
ObjectMeta: metav1.ObjectMeta{
Name: "two",
Labels: map[string]string{
v1.OfferedKey: v1.OfferedValue,
},
Annotations: map[string]string{
v1.PrefixAppCatKey + "/zone": "lpg",
v1.PrefixAppCatKey + "/displayname": "two",
v1.PrefixAppCatKey + "/docs": "https://docs.com",
v1.PrefixAppCatKey + "/product-description": "product desc",
},
},
}
compositionNonOffered = &crossplanev1.Composition{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
v1.OfferedKey: "false",
},
},
}
)
51 changes: 51 additions & 0 deletions pkg/apiserver/appcat/composition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package appcat

import (
"context"
v1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// compositionProvider is an abstraction to interact with the K8s API
type compositionProvider interface {
GetComposition(ctx context.Context, name string, options *metav1.GetOptions) (*v1.Composition, error)
ListCompositions(ctx context.Context, options *metainternalversion.ListOptions) (*v1.CompositionList, error)
WatchCompositions(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
}

type kubeCompositionProvider struct {
Client client.WithWatch
}

func (k *kubeCompositionProvider) GetComposition(ctx context.Context, name string, options *metav1.GetOptions) (*v1.Composition, error) {
c := v1.Composition{}
err := k.Client.Get(ctx, client.ObjectKey{Namespace: "", Name: name}, &c)
return &c, err
}

func (k *kubeCompositionProvider) ListCompositions(ctx context.Context, options *metainternalversion.ListOptions) (*v1.CompositionList, error) {
cl := v1.CompositionList{}
err := k.Client.List(ctx, &cl, &client.ListOptions{
LabelSelector: options.LabelSelector,
FieldSelector: options.FieldSelector,
Limit: options.Limit,
Continue: options.Continue,
})
if err != nil {
return nil, err
}
return &cl, nil
}

func (k *kubeCompositionProvider) WatchCompositions(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error) {
cl := v1.CompositionList{}
return k.Client.Watch(ctx, &cl, &client.ListOptions{
LabelSelector: options.LabelSelector,
FieldSelector: options.FieldSelector,
Limit: options.Limit,
Continue: options.Continue,
})
}
15 changes: 15 additions & 0 deletions pkg/apiserver/appcat/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package appcat

import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/rest"
)

var _ rest.Creater = &appcatStorage{}

func (s *appcatStorage) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
return nil, fmt.Errorf("method not implemented")
}
29 changes: 29 additions & 0 deletions pkg/apiserver/appcat/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package appcat

import (
"context"

v1 "github.com/vshn/appcat-apiserver/apis/appcat/v1"
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/rest"
)

var _ rest.GracefulDeleter = &appcatStorage{}
var _ rest.CollectionDeleter = &appcatStorage{}

func (s *appcatStorage) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
return &v1.AppCat{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}, false, nil
}

func (s *appcatStorage) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) {
return &v1.AppCatList{
Items: []v1.AppCat{},
}, nil
}
Loading

0 comments on commit 28a1f63

Please sign in to comment.