Skip to content

Commit

Permalink
Break provider-gcp up by service
Browse files Browse the repository at this point in the history
- This PR implements the upstream proposal at:
  crossplane/crossplane#3939

- Subpackages belonging to each API group is produced. An example is:
  provider-gcp-cloudplatform.
- ProviderConfig, ProviderConfigUsage and StoreConfig are part of a
  config package named provider-gcp-config.
- The monolith package (containing all the CRDs and associated controllers)
  is still produced.
- Each produced package except for the monolith package has the
  `pkg.crossplane.io/provider-family` label in its package metadata.
- Each service package except for the config package declares a
  dependency to the config package.

Signed-off-by: Alper Rifat Ulucinar <[email protected]>
  • Loading branch information
ulucinar committed Apr 25, 2023
1 parent 4f9a96a commit 9dfe2c6
Show file tree
Hide file tree
Showing 486 changed files with 13,302 additions and 363 deletions.
40 changes: 24 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export TERRAFORM_DOCS_PATH ?= website/docs/r

PLATFORMS ?= linux_amd64 linux_arm64

export PROJECT_NAME := $(PROJECT_NAME)

# -include will silently skip missing files, which allows us
# to load those files with a target in the Makefile. If only
# "include" was used, the make command would fail and refuse
Expand Down Expand Up @@ -43,19 +45,39 @@ export GOPRIVATE = github.com/upbound/*

GO_REQUIRED_VERSION ?= 1.19
GOLANGCILINT_VERSION ?= 1.50.0
GO_STATIC_PACKAGES = $(GO_PROJECT)/cmd/provider $(GO_PROJECT)/cmd/generator
SUBPACKAGES ?= $(shell find cmd/provider -type d -depth 1 | cut -d/ -f3)
GO_STATIC_PACKAGES ?= $(GO_PROJECT)/cmd/generator ${SUBPACKAGES:%=$(GO_PROJECT)/cmd/provider/%}
GO_LDFLAGS += -X $(GO_PROJECT)/internal/version.Version=$(VERSION)
GO_SUBDIRS += cmd internal apis
GO111MODULE = on

export SUBPACKAGES := $(SUBPACKAGES)

-include build/makelib/golang.mk

# ====================================================================================
# Setup XPKG

XPKG_REG_ORGS ?= xpkg.upbound.io/upbound
# NOTE(hasheddan): skip promoting on xpkg.upbound.io as channel tags are
# inferred.
XPKG_REG_ORGS_NO_PROMOTE ?= xpkg.upbound.io/upbound

export XPKG_REG_ORGS := $(XPKG_REG_ORGS)
export XPKG_REG_ORGS_NO_PROMOTE := $(XPKG_REG_ORGS_NO_PROMOTE)

# ====================================================================================
# Setup Kubernetes tools

KIND_VERSION = v0.15.0
UPTEST_VERSION = v0.5.0
# dependency for up
UP_VERSION = v0.16.1
UP_CHANNEL = stable
UPTEST_VERSION = v0.5.0

export UP_VERSION := $(UP_VERSION)
export UP_CHANNEL := $(UP_CHANNEL)

-include build/makelib/k8s_tools.mk

# ====================================================================================
Expand All @@ -65,20 +87,6 @@ REGISTRY_ORGS ?= xpkg.upbound.io/upbound
IMAGES = provider-gcp
-include build/makelib/imagelight.mk

# ====================================================================================
# Setup XPKG

XPKG_REG_ORGS ?= xpkg.upbound.io/upbound
# NOTE(hasheddan): skip promoting on xpkg.upbound.io as channel tags are
# inferred.
XPKG_REG_ORGS_NO_PROMOTE ?= xpkg.upbound.io/upbound
XPKGS = provider-gcp
-include build/makelib/xpkg.mk

# NOTE(hasheddan): we force image building to happen prior to xpkg build so that
# we ensure image is present in daemon.
xpkg.build.provider-gcp: do.build.images

# ====================================================================================
# Targets

Expand Down
2 changes: 2 additions & 0 deletions apis/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ limitations under the License.
//go:generate bash -c "find ../internal/controller -iname 'zz_*' -delete"
//go:generate bash -c "find ../internal/controller -type d -empty -delete"
//go:generate rm -rf ../examples-generated
//go:generate bash -c "find ../cmd/provider -name 'zz_*' -type f -delete"
//go:generate bash -c "find ../cmd/provider -type d -depth 1 -empty -delete"

// Scrape metadata from Terraform registry
//go:generate go run github.com/upbound/upjet/cmd/scraper -n hashicorp/terraform-provider-google -r ../.work/terraform-provider-google/website/docs/r -o ../config/provider-metadata.yaml --prelude-xpath "//text()[contains(., \"subcategory\")]" --resource-prefix google
Expand Down
3 changes: 2 additions & 1 deletion cluster/images/provider-gcp/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ RUN apk --no-cache add ca-certificates bash

ARG TARGETOS
ARG TARGETARCH
ARG APIGROUP

ENV USER_ID=65532

Expand Down Expand Up @@ -47,6 +48,6 @@ ENV TERRAFORM_NATIVE_PROVIDER_PATH ${PLUGIN_DIR}/${TERRAFORM_PROVIDER_DOWNLOAD_N
USER ${USER_ID}
EXPOSE 8080

ADD "bin/${TARGETOS}_${TARGETARCH}/provider" /usr/local/bin/provider
ADD "bin/${TARGETOS}_${TARGETARCH}/${APIGROUP}" /usr/local/bin/provider

ENTRYPOINT ["provider"]
56 changes: 47 additions & 9 deletions cluster/images/provider-gcp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,57 @@ include ../../../build/makelib/common.mk

include ../../../build/makelib/imagelight.mk

# ====================================================================================
# XPKG

-include ../../../build/makelib/xpkg.mk

-include ../../../build/makelib/k8s_tools.mk

# ====================================================================================
# Targets

img.build:
@$(INFO) docker build $(IMAGE)
@$(MAKE) BUILD_ARGS="--load" img.build.shared
@$(OK) docker build $(IMAGE)
@$(INFO) Subpackages to build: $(SUBPACKAGES)
@for g in $(SUBPACKAGES); do \
IMAGE=$$(echo $(IMAGE) | sed -r "s/(.*)-/\1-$${g}-/"); \
$(INFO) Building image $${IMAGE}; \
$(MAKE) BUILD_ARGS="--load" IMAGE=$${IMAGE} APIGROUP=$${g} XPKG_REG_ORGS=$(XPKG_REG_ORGS) img.build.shared; \
$(OK) docker build $${IMAGE}; \
done

img.publish:
@$(INFO) Skipping image publish for $(IMAGE)
@echo Publish is deferred to xpkg machinery
@$(OK) Image publish skipped for $(IMAGE)
# make BRANCH_NAME=main SUBPACKAGES=cloudplatform publish
img.publish: $(UP)
@$(INFO) Subpackages to publish: $(SUBPACKAGES)
@for g in $(SUBPACKAGES); do \
PACKAGE=$(XPKG_REG_ORGS)/$(PROJECT_NAME)-$${g}:$(VERSION); \
if [[ $${g} == "monolith" ]]; then PACKAGE=$(XPKG_REG_ORGS)/$(PROJECT_NAME):$(VERSION); fi; \
$(INFO) Pushing package $${PACKAGE}; \
$(UP) xpkg push $${PACKAGE} \
$(foreach p,$(XPKG_LINUX_PLATFORMS),--package $(XPKG_OUTPUT_DIR)/$(p)/$(PROJECT_NAME)-$${g}-$(VERSION).xpkg ) || $(FAIL); \
$(OK) Done processing $${PACKAGE}. Moving to the next package...; \
done || $(FAIL)

img.build.shared:
img.build.shared: $(UP)
@mkdir -p $(IMAGE_TEMP_DIR)/package/crds || $(FAIL)
@mkdir $(IMAGE_TEMP_DIR)/examples || $(FAIL)
@if [[ $(APIGROUP) == "config" ]]; then \
sed -E "s/{{ APIGROUP }}/$(APIGROUP)/g" $(ROOT_DIR)/package/crossplane-config.yaml > $(IMAGE_TEMP_DIR)/package/crossplane.yaml && \
cp $(ROOT_DIR)/package/crds/gcp.* $(IMAGE_TEMP_DIR)/package/crds/ && \
cp -r $(ROOT_DIR)/examples/gcp $(IMAGE_TEMP_DIR)/examples/; \
elif [[ $(APIGROUP) == "monolith" ]]; then \
cp $(ROOT_DIR)/package/crossplane-monolith.yaml $(IMAGE_TEMP_DIR)/package/crossplane.yaml && \
cp -r $(ROOT_DIR)/package/crds $(IMAGE_TEMP_DIR)/package/ && \
cp -r $(ROOT_DIR)/examples $(IMAGE_TEMP_DIR)/; \
else \
sed -E "s|{{ APIGROUP }}|$(APIGROUP)|g" $(ROOT_DIR)/package/crossplane.yaml | sed -E "s|{{ XPKG_REG_ORGS }}|$(XPKG_REG_ORGS)|g" | sed -E "s|{{ VERSION }}|$(VERSION)|g" > $(IMAGE_TEMP_DIR)/package/crossplane.yaml && \
cp $(ROOT_DIR)/package/crds/$(APIGROUP).* $(IMAGE_TEMP_DIR)/package/crds/ && \
cp -r $(ROOT_DIR)/examples/$(APIGROUP) $(IMAGE_TEMP_DIR)/examples/; \
fi || $(FAIL)
@cp Dockerfile $(IMAGE_TEMP_DIR) || $(FAIL)
@cp terraformrc.hcl $(IMAGE_TEMP_DIR) || $(FAIL)
@cp -r $(OUTPUT_DIR)/bin/ $(IMAGE_TEMP_DIR)/bin || $(FAIL)
@mkdir -p $(IMAGE_TEMP_DIR)/bin/$(PLATFORM)/ || $(FAIL)
@cp -r $(OUTPUT_DIR)/bin/$(PLATFORM)/$(APIGROUP) $(IMAGE_TEMP_DIR)/bin/$(PLATFORM)/ || $(FAIL)
@docker buildx build $(BUILD_ARGS) \
--platform $(IMAGE_PLATFORMS) \
--build-arg TERRAFORM_VERSION=$(TERRAFORM_VERSION) \
Expand All @@ -33,8 +67,12 @@ img.build.shared:
--build-arg TERRAFORM_PROVIDER_DOWNLOAD_NAME=$(TERRAFORM_PROVIDER_DOWNLOAD_NAME) \
--build-arg TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX=$(TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX) \
--build-arg CROSSPLANE_PROVIDER_VERSION=$(VERSION) \
--build-arg APIGROUP=$(APIGROUP) \
-t $(IMAGE) \
$(IMAGE_TEMP_DIR) || $(FAIL)
@$(MAKE) UP=$(UP) XPKG_REG_ORGS=$(XPKG_REG_ORGS) XPKG_REG_ORGS_NO_PROMOTE=$(XPKG_REG_ORGS_NO_PROMOTE) XPKGS=$(PROJECT_NAME)-$(APIGROUP) XPKG_DIR=$(IMAGE_TEMP_DIR)/package XPKG_EXAMPLES_DIR=$(IMAGE_TEMP_DIR)/examples build.xpkg || $(FAIL)

build.xpkg: do.build.xpkgs

img.promote:
@$(INFO) Skipping image promotion from $(FROM_IMAGE) to $(TO_IMAGE)
Expand Down
25 changes: 25 additions & 0 deletions cmd/generator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ func main() {
p := config.GetProvider()
dumpGeneratedResourceList(p, generatedResourceList)
dumpSkippedResourcesCSV(p, skippedResourcesCSV)
// removeCrossResourceReferences(p)
pipeline.Run(p, absRootDir)
//partitionProvider(p, absRootDir)
}

func dumpGeneratedResourceList(p *ujconfig.Provider, targetPath *string) {
Expand Down Expand Up @@ -77,3 +79,26 @@ func dumpSkippedResourcesCSV(p *ujconfig.Provider, targetPath *string) {
panic(fmt.Sprintf("Cannot write skipped resources CSV to file %s: %s", *targetPath, err.Error()))
}
}

func removeCrossResourceReferences(p *ujconfig.Provider) {
// Remove cross-resource references from the provider config.
for k := range p.Resources {
p.Resources[k].References = nil
}
}

// partition the Provider across the API groups
func partitionProvider(p *ujconfig.Provider, absRootDir string) {
partitions := make(map[string]*ujconfig.Provider)
for k, r := range p.Resources {
if partitions[r.ShortGroup] == nil {
p := *p
partitions[r.ShortGroup] = &p
partitions[r.ShortGroup].Resources = make(map[string]*ujconfig.Resource)
}
partitions[r.ShortGroup].Resources[k] = r
}
for g, p := range partitions {
pipeline.Run(p, filepath.Join(absRootDir, g))
}
}
150 changes: 150 additions & 0 deletions cmd/provider/activedirectory/zz_main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
Copyright 2021 The Crossplane Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"context"
"os"
"path/filepath"
"time"

"gopkg.in/alecthomas/kingpin.v2"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection/resourcelock"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"

xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller"
"github.com/crossplane/crossplane-runtime/pkg/feature"
"github.com/crossplane/crossplane-runtime/pkg/logging"
"github.com/crossplane/crossplane-runtime/pkg/ratelimiter"
"github.com/crossplane/crossplane-runtime/pkg/resource"

tjcontroller "github.com/upbound/upjet/pkg/controller"
"github.com/upbound/upjet/pkg/terraform"

"github.com/upbound/provider-gcp/apis"
"github.com/upbound/provider-gcp/apis/v1alpha1"
"github.com/upbound/provider-gcp/config"
"github.com/upbound/provider-gcp/internal/clients"
"github.com/upbound/provider-gcp/internal/controller"
"github.com/upbound/provider-gcp/internal/features"

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

func main() {
var (
app = kingpin.New(filepath.Base(os.Args[0]), "Terraform based Crossplane provider for GCP").DefaultEnvars()
debug = app.Flag("debug", "Run with debug logging.").Short('d').Bool()
syncInterval = app.Flag("sync", "Sync interval controls how often all resources will be double checked for drift.").Short('s').Default("1h").Duration()
pollInterval = app.Flag("poll", "Poll interval controls how often an individual resource should be checked for drift.").Default("10m").Duration()
leaderElection = app.Flag("leader-election", "Use leader election for the controller manager.").Short('l').Default("false").OverrideDefaultFromEnvar("LEADER_ELECTION").Bool()
maxReconcileRate = app.Flag("max-reconcile-rate", "The global maximum rate per second at which resources may checked for drift from the desired state.").Default("10").Int()
pluginProcessTTL = app.Flag("provider-ttl", "TTL for the native plugin processes before they are replaced. Changing the default may increase memory consumption.").Default("100").Int()
terraformVersion = app.Flag("terraform-version", "Terraform version.").Required().Envar("TERRAFORM_VERSION").String()
nativeProviderSource = app.Flag("terraform-provider-source", "Terraform provider source.").Required().Envar("TERRAFORM_PROVIDER_SOURCE").String()
providerVersion = app.Flag("terraform-provider-version", "Terraform provider version.").Required().Envar("TERRAFORM_PROVIDER_VERSION").String()
nativeProviderPath = app.Flag("terraform-native-provider-path", "Terraform native provider path for shared execution.").Default("").Envar("TERRAFORM_NATIVE_PROVIDER_PATH").String()

namespace = app.Flag("namespace", "Namespace used to set as default scope in default secret store config.").Default("crossplane-system").Envar("POD_NAMESPACE").String()
enableExternalSecretStores = app.Flag("enable-external-secret-stores", "Enable support for ExternalSecretStores.").Default("false").Envar("ENABLE_EXTERNAL_SECRET_STORES").Bool()
enableManagementPolicies = app.Flag("enable-management-policies", "Enable support for Management Policies.").Default("false").Envar("ENABLE_MANAGEMENT_POLICIES").Bool()
)

kingpin.MustParse(app.Parse(os.Args[1:]))

zl := zap.New(zap.UseDevMode(*debug))
log := logging.NewLogrLogger(zl.WithName("provider-gcp"))
if *debug {
// The controller-runtime runs with a no-op logger by default. It is
// *very* verbose even at info level, so we only provide it a real
// logger when we're running in debug mode.
ctrl.SetLogger(zl)
}

log.Debug("Starting", "sync-interval", syncInterval.String(),
"poll-interval", pollInterval.String(), "max-reconcile-rate", *maxReconcileRate)

cfg, err := ctrl.GetConfig()
kingpin.FatalIfError(err, "Cannot get API server rest config")

mgr, err := ctrl.NewManager(ratelimiter.LimitRESTConfig(cfg, *maxReconcileRate), ctrl.Options{
LeaderElection: *leaderElection,
LeaderElectionID: "crossplane-leader-election-provider-gcp",
SyncPeriod: syncInterval,
LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
LeaseDuration: func() *time.Duration { d := 60 * time.Second; return &d }(),
RenewDeadline: func() *time.Duration { d := 50 * time.Second; return &d }(),
})
kingpin.FatalIfError(err, "Cannot create controller manager")
kingpin.FatalIfError(apis.AddToScheme(mgr.GetScheme()), "Cannot add GCP APIs to scheme")

// if the native Terraform provider plugin's path is not configured via
// the env. variable TERRAFORM_NATIVE_PROVIDER_PATH or
// the `--terraform-native-provider-path` command-line option,
// we do not use the shared gRPC server and default to the regular
// Terraform CLI behaviour (of forking a plugin process per invocation).
// This removes some complexity for setting up development environments.
var scheduler terraform.ProviderScheduler = terraform.NewNoOpProviderScheduler()
if len(*nativeProviderPath) != 0 {
scheduler = terraform.NewSharedProviderScheduler(log, *pluginProcessTTL, terraform.WithNativeProviderPath(*nativeProviderPath), terraform.WithNativeProviderName("registry.terraform.io/"+*nativeProviderSource))
}

o := tjcontroller.Options{
Options: xpcontroller.Options{
Logger: log,
GlobalRateLimiter: ratelimiter.NewGlobal(*maxReconcileRate),
PollInterval: *pollInterval,
MaxConcurrentReconciles: *maxReconcileRate,
Features: &feature.Flags{},
},
Provider: config.GetProvider(),
WorkspaceStore: terraform.NewWorkspaceStore(log, terraform.WithDisableInit(len(*nativeProviderPath) != 0), terraform.WithProcessReportInterval(*pollInterval)),
SetupFn: clients.TerraformSetupBuilder(*terraformVersion, *nativeProviderSource, *providerVersion, scheduler),
}
if *enableExternalSecretStores {
o.SecretStoreConfigGVK = &v1alpha1.StoreConfigGroupVersionKind
log.Info("Alpha feature enabled", "flag", features.EnableAlphaExternalSecretStores)

// Ensure default store config exists.
kingpin.FatalIfError(resource.Ignore(kerrors.IsAlreadyExists, mgr.GetClient().Create(context.Background(), &v1alpha1.StoreConfig{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
Spec: v1alpha1.StoreConfigSpec{
// NOTE(turkenh): We only set required spec and expect optional
// ones to properly be initialized with CRD level default values.
SecretStoreConfig: xpv1.SecretStoreConfig{
DefaultScope: *namespace,
},
},
Status: v1alpha1.StoreConfigStatus{},
})), "cannot create default store config")
}

if *enableManagementPolicies {
o.Features.Enable(features.EnableAlphaManagementPolicies)
log.Info("Alpha feature enabled", "flag", features.EnableAlphaManagementPolicies)
}

kingpin.FatalIfError(controller.Setup_activedirectory(mgr, o), "Cannot setup GCP controllers")
kingpin.FatalIfError(mgr.Start(ctrl.SetupSignalHandler()), "Cannot start controller manager")
}
Loading

0 comments on commit 9dfe2c6

Please sign in to comment.