mirror of
https://github.com/kubesphere/kubekey.git
synced 2025-12-26 01:22:51 +00:00
feat: add go lint
Signed-off-by: 24sama <jacksama@foxmail.com>
This commit is contained in:
parent
66c521fbd0
commit
08cb08b870
|
|
@ -0,0 +1,29 @@
|
|||
name: golangci-lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, synchronize, reopened]
|
||||
|
||||
# Remove all permissions from GITHUB_TOKEN except metadata.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
working-directory:
|
||||
- ""
|
||||
- test
|
||||
- hack/tools
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3.2.0
|
||||
with:
|
||||
version: v1.48.0
|
||||
working-directory: ${{matrix.working-directory}}
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- containedctx
|
||||
- deadcode
|
||||
- depguard
|
||||
- dogsled
|
||||
- errcheck
|
||||
- exportloopref
|
||||
- gci
|
||||
- goconst
|
||||
- gocritic
|
||||
- gofmt
|
||||
- goimports
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nakedret
|
||||
- nilerr
|
||||
- noctx
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- predeclared
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- thelper
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- whitespace
|
||||
|
||||
linters-settings:
|
||||
godot:
|
||||
# declarations - for top level declaration comments (default);
|
||||
# toplevel - for top level comments;
|
||||
# all - for all comments.
|
||||
scope: toplevel
|
||||
exclude:
|
||||
- '^ \+.*'
|
||||
- '^ ANCHOR.*'
|
||||
ifshort:
|
||||
# Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax.
|
||||
max-decl-chars: 50
|
||||
gci:
|
||||
local-prefixes: "github.com/kubesphere/kubekey"
|
||||
importas:
|
||||
no-unaliased: true
|
||||
alias:
|
||||
# Kubernetes
|
||||
- pkg: k8s.io/api/core/v1
|
||||
alias: corev1
|
||||
- pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
|
||||
alias: apiextensionsv1
|
||||
- pkg: k8s.io/apimachinery/pkg/apis/meta/v1
|
||||
alias: metav1
|
||||
- pkg: k8s.io/apimachinery/pkg/api/errors
|
||||
alias: apierrors
|
||||
- pkg: k8s.io/apimachinery/pkg/util/errors
|
||||
alias: kerrors
|
||||
# Controller Runtime
|
||||
- pkg: sigs.k8s.io/controller-runtime
|
||||
alias: ctrl
|
||||
# CABPK
|
||||
- pkg: sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3
|
||||
alias: bootstrapv1alpha3
|
||||
- pkg: sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha4
|
||||
alias: bootstrapv1alpha4
|
||||
- pkg: sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1
|
||||
alias: bootstrapv1
|
||||
# KCP
|
||||
- pkg: sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3
|
||||
alias: controlplanev1alpha3
|
||||
- pkg: sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha4
|
||||
alias: controlplanev1alpha4
|
||||
- pkg: sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1
|
||||
alias: controlplanev1
|
||||
# CAPI
|
||||
- pkg: sigs.k8s.io/cluster-api/api/v1alpha3
|
||||
alias: clusterv1alpha3
|
||||
- pkg: sigs.k8s.io/cluster-api/api/v1alpha4
|
||||
alias: clusterv1alpha4
|
||||
- pkg: sigs.k8s.io/cluster-api/api/v1beta1
|
||||
alias: clusterv1
|
||||
# CAPI exp
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/api/v1alpha3
|
||||
alias: expv1alpha3
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/api/v1alpha4
|
||||
alias: expv1alpha4
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/api/v1beta1
|
||||
alias: expv1
|
||||
# CAPI exp addons
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/addons/api/v1alpha3
|
||||
alias: addonsv1alpha3
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/addons/api/v1alpha4
|
||||
alias: addonsv1alpha4
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/addons/api/v1beta1
|
||||
alias: addonsv1
|
||||
# CAPI exp runtime
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/runtime/api/v1alpha1
|
||||
alias: runtimev1
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1
|
||||
alias: runtimehooksv1
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/runtime/controllers
|
||||
alias: runtimecontrollers
|
||||
- pkg: sigs.k8s.io/cluster-api/exp/runtime/catalog
|
||||
alias: runtimecatalog
|
||||
- pkg: sigs.k8s.io/cluster-api/internal/runtime/client
|
||||
alias: runtimeclient
|
||||
- pkg: sigs.k8s.io/cluster-api/internal/runtime/registry
|
||||
alias: runtimeregistry
|
||||
- pkg: sigs.k8s.io/cluster-api/internal/webhooks/runtime
|
||||
alias: runtimewebhooks
|
||||
# CAPKK
|
||||
- pkg: github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/api/v1beta1
|
||||
alias: infrav1
|
||||
nolintlint:
|
||||
allow-unused: false
|
||||
allow-leading-space: false
|
||||
require-specific: true
|
||||
staticcheck:
|
||||
go: "1.18"
|
||||
stylecheck:
|
||||
go: "1.18"
|
||||
gosec:
|
||||
excludes:
|
||||
- G307 # Deferring unsafe method "Close" on type "\*os.File"
|
||||
- G108 # Profiling endpoint is automatically exposed on /debug/pprof
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- experimental
|
||||
disabled-checks:
|
||||
- appendAssign
|
||||
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||
- evalOrder
|
||||
- ifElseChain
|
||||
- octalLiteral
|
||||
- regexpSimplify
|
||||
- sloppyReassign
|
||||
- truncateCmp
|
||||
- typeDefFirst
|
||||
- unnamedResult
|
||||
- unnecessaryDefer
|
||||
- whyNoLint
|
||||
- wrapperFunc
|
||||
- commentFormatting
|
||||
- filepathJoin
|
||||
- commentedOutCode
|
||||
unused:
|
||||
go: "1.18"
|
||||
issues:
|
||||
max-same-issues: 0
|
||||
max-issues-per-linter: 0
|
||||
# We are disabling default golangci exclusions because we want to help reviewers to focus on reviewing the most relevant
|
||||
# changes in PRs and avoid nitpicking.
|
||||
exclude-use-default: false
|
||||
exclude-rules:
|
||||
- linters:
|
||||
- revive
|
||||
text: "exported: exported method .*\\.(Reconcile|SetupWithManager|SetupWebhookWithManager) should have comment or be unexported"
|
||||
- linters:
|
||||
- errcheck
|
||||
text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
|
||||
# Exclude some packages or code to require comments, for example test code, or fake clients.
|
||||
- linters:
|
||||
- revive
|
||||
text: exported (method|function|type|const) (.+) should have comment or be unexported
|
||||
source: (func|type).*Fake.*
|
||||
- linters:
|
||||
- revive
|
||||
text: exported (method|function|type|const) (.+) should have comment or be unexported
|
||||
path: fake_\.go
|
||||
- linters:
|
||||
- revive
|
||||
text: exported (method|function|type|const) (.+) should have comment or be unexported
|
||||
path: cmd/clusterctl/internal/test/providers.*.go
|
||||
- linters:
|
||||
- revive
|
||||
text: exported (method|function|type|const) (.+) should have comment or be unexported
|
||||
path: "(framework|e2e)/.*.go"
|
||||
# Disable unparam "always receives" which might not be really
|
||||
# useful when building libraries.
|
||||
- linters:
|
||||
- unparam
|
||||
text: always receives
|
||||
# Dot imports for gomega or ginkgo are allowed
|
||||
# within test files.
|
||||
- path: _test\.go
|
||||
text: should not use dot imports
|
||||
- path: (framework|e2e)/.*.go
|
||||
text: should not use dot imports
|
||||
- path: _test\.go
|
||||
text: cyclomatic complexity
|
||||
# Append should be able to assign to a different var/slice.
|
||||
- linters:
|
||||
- gocritic
|
||||
text: "appendAssign: append result not assigned to the same slice"
|
||||
# ifshort flags variables that are only used in the if-statement even though there is
|
||||
# already a SimpleStmt being used in the if-statement in question.
|
||||
- linters:
|
||||
- ifshort
|
||||
text: "variable .* is only used in the if-statement"
|
||||
path: controllers/mdutil/util.go
|
||||
# Disable linters for conversion
|
||||
- linters:
|
||||
- staticcheck
|
||||
text: "SA1019: in.(.+) is deprecated"
|
||||
path: .*(api|types)\/.*\/conversion.*\.go$
|
||||
- linters:
|
||||
- revive
|
||||
text: exported (method|function|type|const) (.+) should have comment or be unexported
|
||||
path: .*(api|types|test)\/.*\/conversion.*\.go$
|
||||
- linters:
|
||||
- revive
|
||||
text: "var-naming: don't use underscores in Go names;"
|
||||
path: .*(api|types|test)\/.*\/conversion.*\.go$
|
||||
- linters:
|
||||
- revive
|
||||
text: "receiver-naming: receiver name"
|
||||
path: .*(api|types)\/.*\/conversion.*\.go$
|
||||
- linters:
|
||||
- stylecheck
|
||||
text: "ST1003: should not use underscores in Go names;"
|
||||
path: .*(api|types|test)\/.*\/conversion.*\.go$
|
||||
- linters:
|
||||
- stylecheck
|
||||
text: "ST1016: methods on the same type should have the same receiver name"
|
||||
path: .*(api|types)\/.*\/conversion.*\.go$
|
||||
# hack/tools
|
||||
- linters:
|
||||
- typecheck
|
||||
text: import (".+") is a program, not an importable package
|
||||
path: ^tools\.go$
|
||||
|
||||
|
||||
# We don't care about defer in for loops in test files.
|
||||
- linters:
|
||||
- gocritic
|
||||
text: "deferInLoop: Possible resource leak, 'defer' is called in the 'for' loop"
|
||||
path: _test\.go
|
||||
|
||||
run:
|
||||
timeout: 10m
|
||||
build-tags:
|
||||
- tools
|
||||
- e2e
|
||||
skip-files:
|
||||
- "zz_generated.*\\.go$"
|
||||
- "vendored_openapi\\.go$"
|
||||
allow-parallel-runners: true
|
||||
|
|
@ -30,6 +30,8 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
|||
EXP_DIR := exp
|
||||
BIN_DIR := bin
|
||||
TEST_DIR := test
|
||||
TOOLS_DIR := hack/tools
|
||||
TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/$(BIN_DIR))
|
||||
E2E_FRAMEWORK_DIR := $(TEST_DIR)/framework
|
||||
GO_INSTALL := ./scripts/go_install.sh
|
||||
|
||||
|
|
@ -46,6 +48,27 @@ KUSTOMIZE_BIN := kustomize
|
|||
KUSTOMIZE := $(abspath $(TOOLS_BIN_DIR)/$(KUSTOMIZE_BIN)-$(KUSTOMIZE_VER))
|
||||
KUSTOMIZE_PKG := sigs.k8s.io/kustomize/kustomize/v4
|
||||
|
||||
SETUP_ENVTEST_VER := v0.0.0-20211110210527-619e6b92dab9
|
||||
SETUP_ENVTEST_BIN := setup-envtest
|
||||
SETUP_ENVTEST := $(abspath $(TOOLS_BIN_DIR)/$(SETUP_ENVTEST_BIN)-$(SETUP_ENVTEST_VER))
|
||||
SETUP_ENVTEST_PKG := sigs.k8s.io/controller-runtime/tools/setup-envtest
|
||||
|
||||
CONTROLLER_GEN_VER := v0.9.1
|
||||
CONTROLLER_GEN_BIN := controller-gen
|
||||
CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER))
|
||||
CONTROLLER_GEN_PKG := sigs.k8s.io/controller-tools/cmd/controller-gen
|
||||
|
||||
GOTESTSUM_VER := v1.6.4
|
||||
GOTESTSUM_BIN := gotestsum
|
||||
GOTESTSUM := $(abspath $(TOOLS_BIN_DIR)/$(GOTESTSUM_BIN)-$(GOTESTSUM_VER))
|
||||
GOTESTSUM_PKG := gotest.tools/gotestsum
|
||||
|
||||
HADOLINT_VER := v2.10.0
|
||||
HADOLINT_FAILURE_THRESHOLD = warning
|
||||
|
||||
GOLANGCI_LINT_BIN := golangci-lint
|
||||
GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN))
|
||||
|
||||
# Define Docker related variables. Releases should modify and double check these vars.
|
||||
REGISTRY ?= docker.io/kubespheredev
|
||||
PROD_REGISTRY ?= docker.io/kubesphere
|
||||
|
|
@ -54,65 +77,11 @@ PROD_REGISTRY ?= docker.io/kubesphere
|
|||
CAPKK_IMAGE_NAME ?= capkk-manager
|
||||
CAPKK_CONTROLLER_IMG ?= $(REGISTRY)/$(CAPKK_IMAGE_NAME)
|
||||
|
||||
# VERSION defines the project version for the bundle.
|
||||
# Update this value when you upgrade the version of your project.
|
||||
# To re-generate a bundle for another specific version without changing the standard setup, you can:
|
||||
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
|
||||
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
|
||||
VERSION ?= 0.0.1
|
||||
# It is set by Prow GIT_TAG, a git-based tag of the form vYYYYMMDD-hash, e.g., v20210120-v0.3.10-308-gc61521971
|
||||
|
||||
# CHANNELS define the bundle channels used in the bundle.
|
||||
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
|
||||
# To re-generate a bundle for other specific channels without changing the standard setup, you can:
|
||||
# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable)
|
||||
# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable")
|
||||
ifneq ($(origin CHANNELS), undefined)
|
||||
BUNDLE_CHANNELS := --channels=$(CHANNELS)
|
||||
endif
|
||||
|
||||
# DEFAULT_CHANNEL defines the default channel used in the bundle.
|
||||
# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable")
|
||||
# To re-generate a bundle for any other default channel without changing the default setup, you can:
|
||||
# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable)
|
||||
# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable")
|
||||
ifneq ($(origin DEFAULT_CHANNEL), undefined)
|
||||
BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
|
||||
endif
|
||||
BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
|
||||
|
||||
# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images.
|
||||
# This variable is used to construct full image tags for bundle and catalog images.
|
||||
#
|
||||
# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both
|
||||
# kubekey.kubesphere.io/cluster-api-kubekey-provider-bundle:$VERSION and kubekey.kubesphere.io/cluster-api-kubekey-provider-catalog:$VERSION.
|
||||
IMAGE_TAG_BASE ?= kubekey.kubesphere.io/cluster-api-kubekey-provider
|
||||
|
||||
# BUNDLE_IMG defines the image:tag used for the bundle.
|
||||
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
|
||||
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)
|
||||
|
||||
# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command
|
||||
BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
|
||||
|
||||
# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests
|
||||
# You can enable this value if you would like to use SHA Based Digests
|
||||
# To enable set flag to true
|
||||
USE_IMAGE_DIGESTS ?= false
|
||||
ifeq ($(USE_IMAGE_DIGESTS), true)
|
||||
BUNDLE_GEN_FLAGS += --use-image-digests
|
||||
endif
|
||||
|
||||
# Image URL to use all building/pushing image targets
|
||||
IMG ?= controller:latest
|
||||
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
|
||||
ENVTEST_K8S_VERSION = 1.23
|
||||
|
||||
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||
ifeq (,$(shell go env GOBIN))
|
||||
GOBIN=$(shell go env GOPATH)/bin
|
||||
else
|
||||
GOBIN=$(shell go env GOBIN)
|
||||
endif
|
||||
TAG ?= dev
|
||||
ARCH ?= $(shell go env GOARCH)
|
||||
ALL_ARCH = amd64 arm arm64 ppc64le s390x
|
||||
|
||||
# Set build time variables including version details
|
||||
LDFLAGS := $(shell hack/version.sh)
|
||||
|
|
@ -131,11 +100,11 @@ help: ## Display this help.
|
|||
##@ generate:
|
||||
|
||||
.PHONY: manifests
|
||||
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
|
||||
manifests: $(CONTROLLER_GEN) ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
|
||||
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
|
||||
|
||||
.PHONY: generate
|
||||
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
|
||||
generate: $(CONTROLLER_GEN) ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
|
||||
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
|
||||
|
||||
## --------------------------------------
|
||||
|
|
@ -144,13 +113,37 @@ generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and
|
|||
|
||||
##@ lint and verify:
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: ## Run go fmt against code.
|
||||
go fmt ./...
|
||||
.PHONY: lint
|
||||
lint: $(GOLANGCI_LINT) ## Lint the codebase
|
||||
$(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
|
||||
cd $(TEST_DIR); $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
|
||||
cd $(TOOLS_DIR); $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
|
||||
./scripts/ci-lint-dockerfiles.sh $(HADOLINT_VER) $(HADOLINT_FAILURE_THRESHOLD)
|
||||
|
||||
.PHONY: vet
|
||||
vet: ## Run go vet against code.
|
||||
go vet ./...
|
||||
.PHONY: lint-dockerfiles
|
||||
lint-dockerfiles:
|
||||
./scripts/ci-lint-dockerfiles.sh $(HADOLINT_VER) $(HADOLINT_FAILURE_THRESHOLD)
|
||||
|
||||
.PHONY: verify
|
||||
verify: $(addprefix verify-,$(ALL_VERIFY_CHECKS)) lint-dockerfiles ## Run all verify-* targets
|
||||
|
||||
.PHONY: verify-modules
|
||||
verify-modules: generate-modules ## Verify go modules are up to date
|
||||
@if !(git diff --quiet HEAD -- go.sum go.mod $(TOOLS_DIR)/go.mod $(TOOLS_DIR)/go.sum $(TEST_DIR)/go.mod $(TEST_DIR)/go.sum); then \
|
||||
git diff; \
|
||||
echo "go module files are out of date"; exit 1; \
|
||||
fi
|
||||
@if (find . -name 'go.mod' | xargs -n1 grep -q -i 'k8s.io/client-go.*+incompatible'); then \
|
||||
find . -name "go.mod" -exec grep -i 'k8s.io/client-go.*+incompatible' {} \; -print; \
|
||||
echo "go module contains an incompatible client-go version"; exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: verify-gen
|
||||
verify-gen: generate ## Verify go generated files are up to date
|
||||
@if !(git diff --quiet HEAD); then \
|
||||
git diff; \
|
||||
echo "generated files are out of date, run make generate"; exit 1; \
|
||||
fi
|
||||
|
||||
##@ Build
|
||||
|
||||
|
|
@ -193,35 +186,6 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in
|
|||
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
||||
$(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f -
|
||||
|
||||
CONTROLLER_GEN = $(shell pwd)/bin/controller-gen
|
||||
.PHONY: controller-gen
|
||||
controller-gen: ## Download controller-gen locally if necessary.
|
||||
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0)
|
||||
|
||||
KUSTOMIZE = $(shell pwd)/bin/kustomize
|
||||
.PHONY: kustomize
|
||||
kustomize: ## Download kustomize locally if necessary.
|
||||
$(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize@latest)
|
||||
|
||||
ENVTEST = $(shell pwd)/bin/setup-envtest
|
||||
.PHONY: envtest
|
||||
envtest: ## Download envtest-setup locally if necessary.
|
||||
$(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
|
||||
|
||||
# go-get-tool will 'go get' any package $2 and install it to $1.
|
||||
PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
define go-get-tool
|
||||
@[ -f $(1) ] || { \
|
||||
set -e ;\
|
||||
TMP_DIR=$$(mktemp -d) ;\
|
||||
cd $$TMP_DIR ;\
|
||||
go mod init tmp ;\
|
||||
echo "Downloading $(2)" ;\
|
||||
GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\
|
||||
rm -rf $$TMP_DIR ;\
|
||||
}
|
||||
endef
|
||||
|
||||
.PHONY: bundle
|
||||
bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files.
|
||||
operator-sdk generate kustomize manifests -q
|
||||
|
|
@ -368,4 +332,42 @@ set-manifest-pull-policy:
|
|||
.PHONY: set-manifest-image
|
||||
set-manifest-image:
|
||||
$(info Updating kustomize image patch file for manager resource)
|
||||
sed -i'' -e 's@image: .*@image: '"${MANIFEST_IMG}:$(MANIFEST_TAG)"'@' $(TARGET_RESOURCE)
|
||||
sed -i'' -e 's@image: .*@image: '"${MANIFEST_IMG}:$(MANIFEST_TAG)"'@' $(TARGET_RESOURCE)
|
||||
|
||||
## --------------------------------------
|
||||
## Hack / Tools
|
||||
## --------------------------------------
|
||||
|
||||
##@ hack/tools:
|
||||
|
||||
.PHONY: $(CONTROLLER_GEN_BIN)
|
||||
$(CONTROLLER_GEN_BIN): $(CONTROLLER_GEN) ## Build a local copy of controller-gen.
|
||||
|
||||
.PHONY: $(GOTESTSUM_BIN)
|
||||
$(GOTESTSUM_BIN): $(GOTESTSUM) ## Build a local copy of gotestsum.
|
||||
|
||||
.PHONY: $(KUSTOMIZE_BIN)
|
||||
$(KUSTOMIZE_BIN): $(KUSTOMIZE) ## Build a local copy of kustomize.
|
||||
|
||||
.PHONY: $(SETUP_ENVTEST_BIN)
|
||||
$(SETUP_ENVTEST_BIN): $(SETUP_ENVTEST) ## Build a local copy of setup-envtest.
|
||||
|
||||
.PHONY: $(GOLANGCI_LINT_BIN)
|
||||
$(GOLANGCI_LINT_BIN): $(GOLANGCI_LINT) ## Build a local copy of golangci-lint
|
||||
|
||||
$(CONTROLLER_GEN): # Build controller-gen from tools folder.
|
||||
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(CONTROLLER_GEN_PKG) $(CONTROLLER_GEN_BIN) $(CONTROLLER_GEN_VER)
|
||||
|
||||
$(GOTESTSUM): # Build gotestsum from tools folder.
|
||||
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GOTESTSUM_PKG) $(GOTESTSUM_BIN) $(GOTESTSUM_VER)
|
||||
|
||||
$(KUSTOMIZE): # Build kustomize from tools folder.
|
||||
CGO_ENABLED=0 GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(KUSTOMIZE_PKG) $(KUSTOMIZE_BIN) $(KUSTOMIZE_VER)
|
||||
|
||||
$(SETUP_ENVTEST): # Build setup-envtest from tools folder.
|
||||
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(SETUP_ENVTEST_PKG) $(SETUP_ENVTEST_BIN) $(SETUP_ENVTEST_VER)
|
||||
|
||||
$(GOLANGCI_LINT): ../../.github/workflows/golangci-lint.yml # Download golangci-lint using hack script into tools folder.
|
||||
hack/ensure-golangci-lint.sh \
|
||||
-b $(TOOLS_BIN_DIR) \
|
||||
$(shell cat .github/workflows/golangci-lint.yml | grep [[:space:]]version | sed 's/.*version: //')
|
||||
|
|
@ -22,10 +22,12 @@ import (
|
|||
|
||||
// KKCluster condition
|
||||
const (
|
||||
// PrincipalPreparedCondition reports whether the principal is prepared.
|
||||
PrincipalPreparedCondition clusterv1.ConditionType = "PrincipalPrepared"
|
||||
)
|
||||
|
||||
const (
|
||||
// HostReadyCondition reports whether the host is ready to be used.
|
||||
HostReadyCondition clusterv1.ConditionType = "HostReadyCondition"
|
||||
)
|
||||
|
||||
|
|
@ -60,28 +62,38 @@ const (
|
|||
|
||||
// KKInstance condition
|
||||
const (
|
||||
// KKInstanceBootstrappedCondition reports on current status of the instance. Ready indicates the instance is in a init Bootstrapped state.
|
||||
KKInstanceBootstrappedCondition clusterv1.ConditionType = "InstanceBootstrapped"
|
||||
KKInstanceInitOSFailedReason = "InitOSFailed"
|
||||
// KKInstanceInitOSFailedReason used when the instance couldn't initialize os environment.
|
||||
KKInstanceInitOSFailedReason = "InitOSFailed"
|
||||
)
|
||||
|
||||
const (
|
||||
// KKInstanceBinariesReadyCondition reports on whether successful to download binaries.
|
||||
KKInstanceBinariesReadyCondition clusterv1.ConditionType = "InstanceBinariesReady"
|
||||
KKInstanceGetBinaryFailedReason = "GetBinaryFailed"
|
||||
// KKInstanceGetBinaryFailedReason used when the instance couldn't download binaries (or check existed binaries).
|
||||
KKInstanceGetBinaryFailedReason = "GetBinaryFailed"
|
||||
)
|
||||
|
||||
const (
|
||||
KKInstanceCRIReadyCondition clusterv1.ConditionType = "InstanceCRIReady"
|
||||
KKInstanceInstallCRIFailedReason = "InstallCRIFailed"
|
||||
// KKInstanceCRIReadyCondition reports on whether successful to download and install CRI.
|
||||
KKInstanceCRIReadyCondition clusterv1.ConditionType = "InstanceCRIReady"
|
||||
// KKInstanceInstallCRIFailedReason used when the instance couldn't download and install CRI.
|
||||
KKInstanceInstallCRIFailedReason = "InstallCRIFailed"
|
||||
)
|
||||
|
||||
const (
|
||||
KKInstanceProvisionedCondition clusterv1.ConditionType = "InstanceProvisioned"
|
||||
KKInstanceRunCloudConfigFailedReason = "RunCloudConfigFailed"
|
||||
// KKInstanceProvisionedCondition reports on whether the instance is provisioned by cloud-init.
|
||||
KKInstanceProvisionedCondition clusterv1.ConditionType = "InstanceProvisioned"
|
||||
// KKInstanceRunCloudConfigFailedReason used when the instance couldn't be provisioned.
|
||||
KKInstanceRunCloudConfigFailedReason = "RunCloudConfigFailed"
|
||||
)
|
||||
|
||||
const (
|
||||
KKInstanceDeletingBootstrapCondition clusterv1.ConditionType = "InstanceDeletingBootstrapped"
|
||||
KKInstanceClearEnvironmentFailedReason = "ClearEnvironmentFailed"
|
||||
// KKInstanceDeletingBootstrapCondition reports on whether the instance is deleting bootstrap data.
|
||||
KKInstanceDeletingBootstrapCondition clusterv1.ConditionType = "InstanceDeletingBootstrapped"
|
||||
// KKInstanceClearEnvironmentFailedReason used when the instance couldn't be deleting bootstrap data.
|
||||
KKInstanceClearEnvironmentFailedReason = "ClearEnvironmentFailed"
|
||||
|
||||
// CleaningReason (Severity=Info) documents a machine node being cleaned.
|
||||
CleaningReason = "Cleaning"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package v1beta1
|
||||
|
||||
// Default values.
|
||||
const (
|
||||
DockerType = "docker"
|
||||
DefaultDockerVersion = "20.10.8"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 v1beta1 contains the v1beta1 API implementation.
|
||||
package v1beta1
|
||||
|
|
@ -15,8 +15,8 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
// Package v1beta1 contains API Schema definitions for the infrastructure v1beta1 API group
|
||||
//+kubebuilder:object:generate=true
|
||||
//+groupName=infrastructure.cluster.x-k8s.io
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=infrastructure.cluster.x-k8s.io
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ limitations under the License.
|
|||
package v1beta1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
|
||||
"sigs.k8s.io/cluster-api/errors"
|
||||
|
|
@ -53,16 +50,7 @@ type KKClusterSpec struct {
|
|||
Registry Registry `json:"registry"`
|
||||
}
|
||||
|
||||
type ControlPlaneEndPoint struct {
|
||||
// +optional
|
||||
Address string `json:"address"`
|
||||
|
||||
Domain string `json:"domain"`
|
||||
|
||||
// The port on which the API server is serving.
|
||||
Port int32 `json:"port"`
|
||||
}
|
||||
|
||||
// Nodes represents the information about the nodes available to the cluster
|
||||
type Nodes struct {
|
||||
// Auth is the SSH authentication information of all instance. It is a global auth configuration.
|
||||
// +optional
|
||||
|
|
@ -169,18 +157,3 @@ func (k *KKCluster) SetConditions(conditions clusterv1.Conditions) {
|
|||
func init() {
|
||||
SchemeBuilder.Register(&KKCluster{}, &KKClusterList{})
|
||||
}
|
||||
|
||||
// IsZero returns true if both host and port are zero values.
|
||||
func (c ControlPlaneEndPoint) IsZero() bool {
|
||||
return c.Address == "" && c.Port == 0
|
||||
}
|
||||
|
||||
// IsValid returns true if both host and port are non-zero values.
|
||||
func (c ControlPlaneEndPoint) IsValid() bool {
|
||||
return c.Address != "" && c.Port != 0
|
||||
}
|
||||
|
||||
// String returns a formatted version HOST:PORT of this APIEndpoint.
|
||||
func (c ControlPlaneEndPoint) String() string {
|
||||
return net.JoinHostPort(c.Address, fmt.Sprintf("%d", c.Port))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ const (
|
|||
// log is for logging in this package.
|
||||
var kkclusterlog = logf.Log.WithName("kkcluster-resource")
|
||||
|
||||
func (r *KKCluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
func (k *KKCluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(r).
|
||||
For(k).
|
||||
Complete()
|
||||
}
|
||||
|
||||
|
|
@ -53,12 +53,12 @@ func (r *KKCluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
|||
var _ webhook.Defaulter = &KKCluster{}
|
||||
|
||||
// Default implements webhook.Defaulter so a webhook will be registered for the type
|
||||
func (r *KKCluster) Default() {
|
||||
kkclusterlog.Info("default", "name", r.Name)
|
||||
func (k *KKCluster) Default() {
|
||||
kkclusterlog.Info("default", "name", k.Name)
|
||||
|
||||
defaultAuth(&r.Spec.Nodes.Auth)
|
||||
defaultContainerManager(&r.Spec)
|
||||
defaultInstance(&r.Spec)
|
||||
defaultAuth(&k.Spec.Nodes.Auth)
|
||||
defaultContainerManager(&k.Spec)
|
||||
defaultInstance(&k.Spec)
|
||||
}
|
||||
|
||||
func defaultAuth(auth *Auth) {
|
||||
|
|
@ -122,19 +122,19 @@ func defaultInstance(spec *KKClusterSpec) {
|
|||
var _ webhook.Validator = &KKCluster{}
|
||||
|
||||
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *KKCluster) ValidateCreate() error {
|
||||
kkclusterlog.Info("validate create", "name", r.Name)
|
||||
func (k *KKCluster) ValidateCreate() error {
|
||||
kkclusterlog.Info("validate create", "name", k.Name)
|
||||
|
||||
var allErrs field.ErrorList
|
||||
allErrs = append(allErrs, validateClusterNodes(r.Spec.Nodes)...)
|
||||
allErrs = append(allErrs, validateLoadBalancer(r.Spec.ControlPlaneLoadBalancer)...)
|
||||
allErrs = append(allErrs, validateClusterNodes(k.Spec.Nodes)...)
|
||||
allErrs = append(allErrs, validateLoadBalancer(k.Spec.ControlPlaneLoadBalancer)...)
|
||||
|
||||
return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs)
|
||||
return aggregateObjErrors(k.GroupVersionKind().GroupKind(), k.Name, allErrs)
|
||||
}
|
||||
|
||||
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *KKCluster) ValidateUpdate(old runtime.Object) error {
|
||||
kkclusterlog.Info("validate update", "name", r.Name)
|
||||
func (k *KKCluster) ValidateUpdate(old runtime.Object) error {
|
||||
kkclusterlog.Info("validate update", "name", k.Name)
|
||||
|
||||
var allErrs field.ErrorList
|
||||
oldC, ok := old.(*KKCluster)
|
||||
|
|
@ -144,8 +144,8 @@ func (r *KKCluster) ValidateUpdate(old runtime.Object) error {
|
|||
|
||||
newLoadBalancer := &KKLoadBalancerSpec{}
|
||||
|
||||
if r.Spec.ControlPlaneLoadBalancer != nil {
|
||||
newLoadBalancer = r.Spec.ControlPlaneLoadBalancer.DeepCopy()
|
||||
if k.Spec.ControlPlaneLoadBalancer != nil {
|
||||
newLoadBalancer = k.Spec.ControlPlaneLoadBalancer.DeepCopy()
|
||||
}
|
||||
|
||||
if oldC.Spec.ControlPlaneLoadBalancer != nil {
|
||||
|
|
@ -154,17 +154,17 @@ func (r *KKCluster) ValidateUpdate(old runtime.Object) error {
|
|||
if !cmp.Equal(newLoadBalancer, existingLoadBalancer) {
|
||||
allErrs = append(allErrs,
|
||||
field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer"),
|
||||
r.Spec.ControlPlaneLoadBalancer, "field is immutable"),
|
||||
k.Spec.ControlPlaneLoadBalancer, "field is immutable"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateClusterNodes(r.Spec.Nodes)...)
|
||||
return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs)
|
||||
allErrs = append(allErrs, validateClusterNodes(k.Spec.Nodes)...)
|
||||
return aggregateObjErrors(k.GroupVersionKind().GroupKind(), k.Name, allErrs)
|
||||
}
|
||||
|
||||
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *KKCluster) ValidateDelete() error {
|
||||
func (k *KKCluster) ValidateDelete() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ func init() {
|
|||
SchemeBuilder.Register(&KKClusterTemplate{}, &KKClusterTemplateList{})
|
||||
}
|
||||
|
||||
// KKClusterTemplateResource Standard object's metadata
|
||||
type KKClusterTemplateResource struct {
|
||||
// Standard object's metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
// log is for logging in this package.
|
||||
var kkclustertemplatelog = logf.Log.WithName("kkclustertemplate-resource")
|
||||
|
||||
// SetupWebhookWithManager sets up and registers the webhook with the manager.
|
||||
func (r *KKClusterTemplate) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(r).
|
||||
|
|
|
|||
|
|
@ -36,9 +36,10 @@ var (
|
|||
// InstanceStatePending is the string representing an instance in a pending state.
|
||||
InstanceStatePending = InstanceState("pending")
|
||||
|
||||
// InstanceStateBootstrapping is the string representing an instance in a bootstrapping state.
|
||||
InstanceStateBootstrapping = InstanceState("bootstrapping")
|
||||
|
||||
//InstanceStateBootstrapped = InstanceState("bootstrapped")
|
||||
// InstanceStateBootstrapped = InstanceState("bootstrapped")
|
||||
|
||||
// InstanceStateRunning is the string representing an instance in a running state.
|
||||
InstanceStateRunning = InstanceState("running")
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
package v1beta1
|
||||
|
||||
// Role represents a role of a node.
|
||||
type Role string
|
||||
|
||||
// Internal roles.
|
||||
const (
|
||||
ControlPlane Role = "control-plane"
|
||||
Master Role = "master"
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
Copyright 2022.
|
||||
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
//+kubebuilder:scaffold:imports
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
)
|
||||
|
||||
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
|
||||
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
|
||||
|
||||
var cfg *rest.Config
|
||||
var k8sClient client.Client
|
||||
var testEnv *envtest.Environment
|
||||
var ctx context.Context
|
||||
var cancel context.CancelFunc
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
RunSpecsWithDefaultAndCustomReporters(t,
|
||||
"Webhook Suite",
|
||||
[]Reporter{printer.NewlineReporter{}})
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
|
||||
|
||||
ctx, cancel = context.WithCancel(context.TODO())
|
||||
|
||||
By("bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
|
||||
ErrorIfCRDPathMissing: false,
|
||||
WebhookInstallOptions: envtest.WebhookInstallOptions{
|
||||
Paths: []string{filepath.Join("..", "..", "config", "webhook")},
|
||||
},
|
||||
}
|
||||
|
||||
cfg, err := testEnv.Start()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cfg).NotTo(BeNil())
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
err = AddToScheme(scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = admissionv1beta1.AddToScheme(scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = admissionv1beta1.AddToScheme(scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
//+kubebuilder:scaffold:scheme
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(k8sClient).NotTo(BeNil())
|
||||
|
||||
// start webhook server using Manager
|
||||
webhookInstallOptions := &testEnv.WebhookInstallOptions
|
||||
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Host: webhookInstallOptions.LocalServingHost,
|
||||
Port: webhookInstallOptions.LocalServingPort,
|
||||
CertDir: webhookInstallOptions.LocalServingCertDir,
|
||||
LeaderElection: false,
|
||||
MetricsBindAddress: "0",
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = (&KKCluster{}).SetupWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = (&KKClusterTemplate{}).SetupWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
//+kubebuilder:scaffold:webhook
|
||||
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
err = mgr.Start(ctx)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}()
|
||||
|
||||
// wait for the webhook server to get ready
|
||||
dialer := &net.Dialer{Timeout: time.Second}
|
||||
addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort)
|
||||
Eventually(func() error {
|
||||
conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn.Close()
|
||||
return nil
|
||||
}).Should(Succeed())
|
||||
|
||||
}, 60)
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
cancel()
|
||||
By("tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
|
@ -68,21 +68,6 @@ func (in *ContainerManager) DeepCopy() *ContainerManager {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ControlPlaneEndPoint) DeepCopyInto(out *ControlPlaneEndPoint) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneEndPoint.
|
||||
func (in *ControlPlaneEndPoint) DeepCopy() *ControlPlaneEndPoint {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ControlPlaneEndPoint)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KKCluster) DeepCopyInto(out *KKCluster) {
|
||||
*out = *in
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.6.1
|
||||
controller-gen.kubebuilder.io/version: v0.9.1
|
||||
creationTimestamp: null
|
||||
name: kkclusters.infrastructure.cluster.x-k8s.io
|
||||
spec:
|
||||
|
|
@ -188,6 +187,7 @@ spec:
|
|||
roles:
|
||||
description: Roles is the role of the machine.
|
||||
items:
|
||||
description: Role represents a role of a node.
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
|
|
@ -373,9 +373,3 @@ spec:
|
|||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.6.1
|
||||
controller-gen.kubebuilder.io/version: v0.9.1
|
||||
creationTimestamp: null
|
||||
name: kkclustertemplates.infrastructure.cluster.x-k8s.io
|
||||
spec:
|
||||
|
|
@ -46,6 +45,7 @@ spec:
|
|||
description: KKClusterTemplateSpec defines the desired state of KKClusterTemplate
|
||||
properties:
|
||||
template:
|
||||
description: KKClusterTemplateResource Standard object's metadata
|
||||
properties:
|
||||
metadata:
|
||||
description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata'
|
||||
|
|
@ -213,6 +213,7 @@ spec:
|
|||
roles:
|
||||
description: Roles is the role of the machine.
|
||||
items:
|
||||
description: Role represents a role of a node.
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
|
|
@ -321,9 +322,3 @@ spec:
|
|||
served: true
|
||||
storage: true
|
||||
subresources: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.6.1
|
||||
controller-gen.kubebuilder.io/version: v0.9.1
|
||||
creationTimestamp: null
|
||||
name: kkinstances.infrastructure.cluster.x-k8s.io
|
||||
spec:
|
||||
|
|
@ -107,6 +106,7 @@ spec:
|
|||
roles:
|
||||
description: Roles is the role of the machine.
|
||||
items:
|
||||
description: Role represents a role of a node.
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
|
|
@ -197,9 +197,3 @@ spec:
|
|||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.6.1
|
||||
controller-gen.kubebuilder.io/version: v0.9.1
|
||||
creationTimestamp: null
|
||||
name: kkmachines.infrastructure.cluster.x-k8s.io
|
||||
spec:
|
||||
|
|
@ -81,6 +80,7 @@ spec:
|
|||
roles:
|
||||
description: Roles is the role of the machine.
|
||||
items:
|
||||
description: Role represents a role of a node.
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
|
|
@ -193,9 +193,3 @@ spec:
|
|||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.6.1
|
||||
controller-gen.kubebuilder.io/version: v0.9.1
|
||||
creationTimestamp: null
|
||||
name: kkmachinetemplates.infrastructure.cluster.x-k8s.io
|
||||
spec:
|
||||
|
|
@ -90,6 +89,7 @@ spec:
|
|||
roles:
|
||||
description: Roles is the role of the machine.
|
||||
items:
|
||||
description: Role represents a role of a node.
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
|
|
@ -104,9 +104,3 @@ spec:
|
|||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: MutatingWebhookConfiguration
|
||||
|
|
@ -46,7 +45,6 @@ webhooks:
|
|||
resources:
|
||||
- kkclustertemplates
|
||||
sideEffects: None
|
||||
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 controllers implements controllers.
|
||||
package controllers
|
||||
|
|
@ -25,7 +25,6 @@ import (
|
|||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
apimachinerytypes "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
capierrors "sigs.k8s.io/cluster-api/errors"
|
||||
capiutil "sigs.k8s.io/cluster-api/util"
|
||||
"sigs.k8s.io/cluster-api/util/patch"
|
||||
|
|
@ -36,12 +35,8 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/scope"
|
||||
)
|
||||
|
||||
func (r *KKMachineReconciler) createInstance(
|
||||
ctx context.Context,
|
||||
machineScope *scope.MachineScope,
|
||||
kkInstanceScope scope.KKInstanceScope,
|
||||
) (*infrav1.KKInstance, error) {
|
||||
|
||||
func (r *KKMachineReconciler) createInstance(ctx context.Context, machineScope *scope.MachineScope,
|
||||
kkInstanceScope scope.KKInstanceScope) (*infrav1.KKInstance, error) {
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
log.V(4).Info("Creating KKInstance")
|
||||
|
||||
|
|
@ -61,7 +56,7 @@ func (r *KKMachineReconciler) createInstance(
|
|||
instanceSpec.Arch = "amd64"
|
||||
}
|
||||
|
||||
// todo: if it need to append a random suffix to the name string
|
||||
// todo: if it needs to append a random suffix to the name string
|
||||
instanceID := instanceSpec.Name
|
||||
|
||||
gv := infrav1.GroupVersion
|
||||
|
|
@ -95,10 +90,6 @@ func (r *KKMachineReconciler) createInstance(
|
|||
return instance, nil
|
||||
}
|
||||
|
||||
func (r *KKMachineReconciler) generateInstanceID(instanceSpec *infrav1.KKInstanceSpec) string {
|
||||
return names.SimpleNameGenerator.GenerateName(instanceSpec.Name + "-")
|
||||
}
|
||||
|
||||
func (r *KKMachineReconciler) getUnassignedInstanceSpec(machineScope *scope.MachineScope, kkInstanceScope scope.KKInstanceScope) (*infrav1.KKInstanceSpec, error) {
|
||||
var instanceSpecs []infrav1.KKInstanceSpec
|
||||
if len(machineScope.GetRoles()) != 0 {
|
||||
|
|
@ -118,18 +109,19 @@ func (r *KKMachineReconciler) getUnassignedInstanceSpec(machineScope *scope.Mach
|
|||
}
|
||||
|
||||
for _, spec := range instanceSpecs {
|
||||
if _, ok := instancesMap[spec.InternalAddress]; !ok {
|
||||
auth := kkInstanceScope.GlobalAuth().DeepCopy()
|
||||
if err := mergo.Merge(&spec.Auth, auth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cm := kkInstanceScope.GlobalContainerManager().DeepCopy()
|
||||
if err := mergo.Merge(&spec.ContainerManager, cm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &spec, nil
|
||||
if _, ok := instancesMap[spec.InternalAddress]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
auth := kkInstanceScope.GlobalAuth().DeepCopy()
|
||||
if err := mergo.Merge(&spec.Auth, auth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cm := kkInstanceScope.GlobalContainerManager().DeepCopy()
|
||||
if err := mergo.Merge(&spec.ContainerManager, cm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &spec, nil
|
||||
}
|
||||
return nil, errors.New("unassigned instance not found")
|
||||
}
|
||||
|
|
@ -143,7 +135,7 @@ func (r *KKMachineReconciler) deleteInstance(ctx context.Context, instance *infr
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *KKMachineReconciler) SetNodeProviderID(ctx context.Context, machineScope *scope.MachineScope, instance *infrav1.KKInstance) error {
|
||||
func (r *KKMachineReconciler) setNodeProviderID(ctx context.Context, machineScope *scope.MachineScope, instance *infrav1.KKInstance) error {
|
||||
// Usually a cloud provider will do this, but there is no kubekey-cloud provider.
|
||||
// Requeue if there is an error, as this is likely momentary load balancer
|
||||
// state changes during control plane provisioning.
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ func (r *KKClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
|
|||
return r.reconcileNormal(ctx, clusterScope)
|
||||
}
|
||||
|
||||
func (r *KKClusterReconciler) reconcileDelete(ctx context.Context, clusterScope *scope.ClusterScope) (reconcile.Result, error) {
|
||||
func (r *KKClusterReconciler) reconcileDelete(ctx context.Context, clusterScope *scope.ClusterScope) (ctrl.Result, error) { //nolint:unparam
|
||||
log := ctrl.LoggerFrom(ctx)
|
||||
log.V(4).Info("Reconcile KKCluster delete")
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ func (r *KKClusterReconciler) reconcileNormal(ctx context.Context, clusterScope
|
|||
if _, err := net.LookupIP(kkCluster.Spec.ControlPlaneLoadBalancer.Host); err != nil {
|
||||
conditions.MarkFalse(kkCluster, infrav1.ExternalLoadBalancerReadyCondition, infrav1.WaitForDNSNameResolveReason, clusterv1.ConditionSeverityInfo, "")
|
||||
clusterScope.Info("Waiting on API server DNS name to resolve")
|
||||
return reconcile.Result{RequeueAfter: 15 * time.Second}, nil // nolint:nilerr
|
||||
return reconcile.Result{RequeueAfter: 15 * time.Second}, nil //nolint:nilerr
|
||||
}
|
||||
conditions.MarkTrue(kkCluster, infrav1.ExternalLoadBalancerReadyCondition)
|
||||
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ import (
|
|||
|
||||
const (
|
||||
defaultRequeueWait = 30 * time.Second
|
||||
DefaultKKInstanceInterval = 5 * time.Second
|
||||
DefaultKKInstanceTimeout = 10 * time.Minute
|
||||
defaultKKInstanceInterval = 5 * time.Second
|
||||
defaultKKInstanceTimeout = 10 * time.Minute
|
||||
)
|
||||
|
||||
// KKInstanceReconciler reconciles a KKInstance object
|
||||
|
|
@ -118,10 +118,10 @@ func (r *KKInstanceReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma
|
|||
log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
if r.WaitKKInstanceInterval.Nanoseconds() == 0 {
|
||||
r.WaitKKInstanceInterval = DefaultKKInstanceInterval
|
||||
r.WaitKKInstanceInterval = defaultKKInstanceInterval
|
||||
}
|
||||
if r.WaitKKInstanceTimeout.Nanoseconds() == 0 {
|
||||
r.WaitKKInstanceTimeout = DefaultKKInstanceTimeout
|
||||
r.WaitKKInstanceTimeout = defaultKKInstanceTimeout
|
||||
}
|
||||
|
||||
c, err := ctrl.NewControllerManagedBy(mgr).
|
||||
|
|
@ -421,6 +421,8 @@ func (r *KKInstanceReconciler) requestsForCluster(log logr.Logger, namespace, na
|
|||
return result
|
||||
}
|
||||
|
||||
// KKMachineToKKInstanceMapFunc returns a handler.ToRequestsFunc that watches for
|
||||
// KKMachine events and returns reconciliation requests for an KKInstance object.
|
||||
func (r *KKInstanceReconciler) KKMachineToKKInstanceMapFunc(log logr.Logger) handler.MapFunc {
|
||||
log.V(4).Info("KKMachineToKKInstanceMapFunc")
|
||||
return func(o client.Object) []reconcile.Request {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/scope"
|
||||
)
|
||||
|
||||
func (r *KKInstanceReconciler) reconcilePing(ctx context.Context, instanceScope *scope.InstanceScope) error {
|
||||
func (r *KKInstanceReconciler) reconcilePing(_ context.Context, instanceScope *scope.InstanceScope) error {
|
||||
instanceScope.Info("Reconcile ping")
|
||||
|
||||
sshClient := r.getSSHClient(instanceScope)
|
||||
|
|
@ -45,7 +45,8 @@ func (r *KKInstanceReconciler) reconcilePing(ctx context.Context, instanceScope
|
|||
return err
|
||||
}
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileDeletingBootstrap(ctx context.Context, sshClient ssh.Interface, instanceScope *scope.InstanceScope, lbScope scope.LBScope) (err error) {
|
||||
func (r *KKInstanceReconciler) reconcileDeletingBootstrap(_ context.Context, sshClient ssh.Interface, instanceScope *scope.InstanceScope,
|
||||
lbScope scope.LBScope) (err error) {
|
||||
instanceScope.Info("Reconcile deleting bootstrap")
|
||||
|
||||
defer func() {
|
||||
|
|
@ -77,9 +78,8 @@ func (r *KKInstanceReconciler) reconcileDeletingBootstrap(ctx context.Context, s
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileBootstrap(ctx context.Context, sshClient ssh.Interface,
|
||||
instanceScope *scope.InstanceScope, kkInstanceScope scope.KKInstanceScope, lbScope scope.LBScope) (err error) {
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileBootstrap(_ context.Context, sshClient ssh.Interface, instanceScope *scope.InstanceScope,
|
||||
_ scope.KKInstanceScope, lbScope scope.LBScope) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
conditions.MarkFalse(
|
||||
|
|
@ -125,9 +125,8 @@ func (r *KKInstanceReconciler) reconcileBootstrap(ctx context.Context, sshClient
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileBinaryService(ctx context.Context, sshClient ssh.Interface,
|
||||
instanceScope *scope.InstanceScope, kkInstanceScope scope.KKInstanceScope, lbScope scope.LBScope) (err error) {
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileBinaryService(_ context.Context, sshClient ssh.Interface, instanceScope *scope.InstanceScope,
|
||||
kkInstanceScope scope.KKInstanceScope, _ scope.LBScope) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
conditions.MarkFalse(
|
||||
|
|
@ -158,12 +157,8 @@ func (r *KKInstanceReconciler) reconcileBinaryService(ctx context.Context, sshCl
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileContainerManager(
|
||||
ctx context.Context,
|
||||
sshClient ssh.Interface,
|
||||
instanceScope *scope.InstanceScope,
|
||||
scope scope.KKInstanceScope, lbScope scope.LBScope) (err error) {
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileContainerManager(_ context.Context, sshClient ssh.Interface, instanceScope *scope.InstanceScope,
|
||||
scope scope.KKInstanceScope, _ scope.LBScope) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
conditions.MarkFalse(
|
||||
|
|
@ -200,9 +195,8 @@ func (r *KKInstanceReconciler) reconcileContainerManager(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileProvisioning(ctx context.Context, sshClient ssh.Interface,
|
||||
instanceScope *scope.InstanceScope, kkInstanceScope scope.KKInstanceScope, lbScope scope.LBScope) (err error) {
|
||||
|
||||
func (r *KKInstanceReconciler) reconcileProvisioning(ctx context.Context, sshClient ssh.Interface, instanceScope *scope.InstanceScope,
|
||||
_ scope.KKInstanceScope, _ scope.LBScope) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
conditions.MarkFalse(
|
||||
|
|
|
|||
|
|
@ -237,13 +237,8 @@ func (r *KKMachineReconciler) reconcileDeleteKKInstance(ctx context.Context, mac
|
|||
return instance, nil
|
||||
}
|
||||
|
||||
func (r *KKMachineReconciler) reconcileNormal(
|
||||
ctx context.Context,
|
||||
machineScope *scope.MachineScope,
|
||||
clusterScope pkg.ClusterScoper,
|
||||
kkInstanceScope scope.KKInstanceScope,
|
||||
) (ctrl.Result, error) {
|
||||
|
||||
func (r *KKMachineReconciler) reconcileNormal(ctx context.Context, machineScope *scope.MachineScope, _ pkg.ClusterScoper,
|
||||
kkInstanceScope scope.KKInstanceScope) (ctrl.Result, error) {
|
||||
machineScope.Info("Reconcile KKMachine normal")
|
||||
|
||||
// If the KKMachine is in an error state, return early.
|
||||
|
|
@ -332,7 +327,7 @@ func (r *KKMachineReconciler) reconcileNormal(
|
|||
conditions.MarkFalse(machineScope.KKMachine, infrav1.InstanceReadyCondition, infrav1.InstanceCleanedReason, clusterv1.ConditionSeverityWarning, "")
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
case infrav1.InstanceStateRunning:
|
||||
if err := r.SetNodeProviderID(ctx, machineScope, instance); err != nil {
|
||||
if err := r.setNodeProviderID(ctx, machineScope, instance); err != nil {
|
||||
machineScope.Error(err, "failed to patch the Kubernetes node with the machine providerID")
|
||||
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||
}
|
||||
|
|
@ -370,41 +365,25 @@ func (r *KKMachineReconciler) findInstance(ctx context.Context, machineScope *sc
|
|||
if errors.Is(err, noderefutil.ErrEmptyProviderID) {
|
||||
machineScope.Info("KKMachine does not have an instance id")
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "failed to parse Spec.ProviderID")
|
||||
}
|
||||
} else {
|
||||
machineScope.V(4).Info("KKMachine has an instance id", "instance-id", pid.ID())
|
||||
// If the ProviderID is populated, describe the instance using the ID.
|
||||
id := pointer.StringPtr(pid.ID())
|
||||
return nil, errors.Wrapf(err, "failed to parse Spec.ProviderID")
|
||||
}
|
||||
|
||||
obj := client.ObjectKey{
|
||||
Namespace: machineScope.KKMachine.Namespace,
|
||||
Name: *id,
|
||||
}
|
||||
if err := r.Client.Get(ctx, obj, kkInstance); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
machineScope.V(4).Info("KKMachine has an instance id", "instance-id", pid.ID())
|
||||
// If the ProviderID is populated, describe the instance using the ID.
|
||||
id := pointer.StringPtr(pid.ID())
|
||||
|
||||
obj := client.ObjectKey{
|
||||
Namespace: machineScope.KKMachine.Namespace,
|
||||
Name: *id,
|
||||
}
|
||||
if err := r.Client.Get(ctx, obj, kkInstance); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The only case where the instance is nil here is when the providerId is empty and instance could not be found by tags.
|
||||
return kkInstance, nil
|
||||
}
|
||||
|
||||
func (r *KKMachineReconciler) getInfraCluster(ctx context.Context, cluster *clusterv1.Cluster, kkMachine *infrav1.KKMachine) (*infrav1.KKCluster, error) {
|
||||
kkCluster := &infrav1.KKCluster{}
|
||||
|
||||
infraClusterName := client.ObjectKey{
|
||||
Namespace: kkMachine.Namespace,
|
||||
Name: cluster.Spec.InfrastructureRef.Name,
|
||||
}
|
||||
|
||||
if err := r.Client.Get(ctx, infraClusterName, kkCluster); err != nil {
|
||||
return nil, nil // nolint:nilerr
|
||||
}
|
||||
|
||||
return kkCluster, nil
|
||||
}
|
||||
|
||||
func (r *KKMachineReconciler) indexKKMachineByInstanceID(o client.Object) []string {
|
||||
kkMachine, ok := o.(*infrav1.KKMachine)
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -23,21 +23,20 @@ import (
|
|||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
infrastructurev1beta1 "github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/api/v1beta1"
|
||||
infrav1 "github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/api/v1beta1"
|
||||
//+kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
|
||||
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
|
||||
|
||||
var cfg *rest.Config
|
||||
// var cfg *rest.Config
|
||||
var k8sClient client.Client
|
||||
var testEnv *envtest.Environment
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ var _ = BeforeSuite(func() {
|
|||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cfg).NotTo(BeNil())
|
||||
|
||||
err = infrastructurev1beta1.AddToScheme(scheme.Scheme)
|
||||
err = infrav1.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
//+kubebuilder:scaffold:scheme
|
||||
|
|
|
|||
|
|
@ -0,0 +1,422 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2021 The Kubernetes 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.
|
||||
|
||||
# NOTE: This script is copied from from https://raw.githubusercontent.com/golangci/golangci-lint/main/install.sh.
|
||||
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
this=$1
|
||||
cat <<EOF
|
||||
$this: download go binaries for golangci/golangci-lint
|
||||
|
||||
Usage: $this [-b] bindir [-d] [tag]
|
||||
-b sets bindir or installation directory, Defaults to ./bin
|
||||
-d turns on debug logging
|
||||
[tag] is a tag from
|
||||
https://github.com/golangci/golangci-lint/releases
|
||||
If tag is missing, then the latest will be used.
|
||||
|
||||
Generated by godownloader
|
||||
https://github.com/goreleaser/godownloader
|
||||
|
||||
EOF
|
||||
exit 2
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
#BINDIR is ./bin unless set be ENV
|
||||
# over-ridden by flag below
|
||||
|
||||
BINDIR=${BINDIR:-./bin}
|
||||
while getopts "b:dh?x" arg; do
|
||||
case "$arg" in
|
||||
b) BINDIR="$OPTARG" ;;
|
||||
d) log_set_priority 10 ;;
|
||||
h | \?) usage "$0" ;;
|
||||
x) set -x ;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
TAG=$1
|
||||
}
|
||||
# this function wraps all the destructive operations
|
||||
# if a curl|bash cuts off the end of the script due to
|
||||
# network, either nothing will happen or will syntax error
|
||||
# out preventing half-done work
|
||||
execute() {
|
||||
tmpdir=$(mktemp -d)
|
||||
log_debug "downloading files into ${tmpdir}"
|
||||
http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
|
||||
http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
|
||||
hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
|
||||
srcdir="${tmpdir}/${NAME}"
|
||||
rm -rf "${srcdir}"
|
||||
(cd "${tmpdir}" && untar "${TARBALL}")
|
||||
test ! -d "${BINDIR}" && install -d "${BINDIR}"
|
||||
for binexe in $BINARIES; do
|
||||
if [ "$OS" = "windows" ]; then
|
||||
binexe="${binexe}.exe"
|
||||
fi
|
||||
install "${srcdir}/${binexe}" "${BINDIR}/"
|
||||
log_info "installed ${BINDIR}/${binexe}"
|
||||
done
|
||||
rm -rf "${tmpdir}"
|
||||
}
|
||||
get_binaries() {
|
||||
case "$PLATFORM" in
|
||||
darwin/amd64) BINARIES="golangci-lint" ;;
|
||||
darwin/arm64) BINARIES="golangci-lint" ;;
|
||||
darwin/armv6) BINARIES="golangci-lint" ;;
|
||||
darwin/armv7) BINARIES="golangci-lint" ;;
|
||||
darwin/mips64) BINARIES="golangci-lint" ;;
|
||||
darwin/mips64le) BINARIES="golangci-lint" ;;
|
||||
darwin/ppc64le) BINARIES="golangci-lint" ;;
|
||||
darwin/s390x) BINARIES="golangci-lint" ;;
|
||||
freebsd/386) BINARIES="golangci-lint" ;;
|
||||
freebsd/amd64) BINARIES="golangci-lint" ;;
|
||||
freebsd/armv6) BINARIES="golangci-lint" ;;
|
||||
freebsd/armv7) BINARIES="golangci-lint" ;;
|
||||
freebsd/mips64) BINARIES="golangci-lint" ;;
|
||||
freebsd/mips64le) BINARIES="golangci-lint" ;;
|
||||
freebsd/ppc64le) BINARIES="golangci-lint" ;;
|
||||
freebsd/s390x) BINARIES="golangci-lint" ;;
|
||||
linux/386) BINARIES="golangci-lint" ;;
|
||||
linux/amd64) BINARIES="golangci-lint" ;;
|
||||
linux/arm64) BINARIES="golangci-lint" ;;
|
||||
linux/armv6) BINARIES="golangci-lint" ;;
|
||||
linux/armv7) BINARIES="golangci-lint" ;;
|
||||
linux/mips64) BINARIES="golangci-lint" ;;
|
||||
linux/mips64le) BINARIES="golangci-lint" ;;
|
||||
linux/ppc64le) BINARIES="golangci-lint" ;;
|
||||
linux/s390x) BINARIES="golangci-lint" ;;
|
||||
windows/386) BINARIES="golangci-lint" ;;
|
||||
windows/amd64) BINARIES="golangci-lint" ;;
|
||||
windows/arm64) BINARIES="golangci-lint" ;;
|
||||
windows/armv6) BINARIES="golangci-lint" ;;
|
||||
windows/armv7) BINARIES="golangci-lint" ;;
|
||||
windows/mips64) BINARIES="golangci-lint" ;;
|
||||
windows/mips64le) BINARIES="golangci-lint" ;;
|
||||
windows/ppc64le) BINARIES="golangci-lint" ;;
|
||||
windows/s390x) BINARIES="golangci-lint" ;;
|
||||
*)
|
||||
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
tag_to_version() {
|
||||
if [ -z "${TAG}" ]; then
|
||||
log_info "checking GitHub for latest tag"
|
||||
else
|
||||
log_info "checking GitHub for tag '${TAG}'"
|
||||
fi
|
||||
REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
|
||||
if test -z "$REALTAG"; then
|
||||
log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
|
||||
exit 1
|
||||
fi
|
||||
# if version starts with 'v', remove it
|
||||
TAG="$REALTAG"
|
||||
VERSION=${TAG#v}
|
||||
}
|
||||
adjust_format() {
|
||||
# change format (tar.gz or zip) based on OS
|
||||
case ${OS} in
|
||||
windows) FORMAT=zip ;;
|
||||
esac
|
||||
true
|
||||
}
|
||||
adjust_os() {
|
||||
# adjust archive name based on OS
|
||||
true
|
||||
}
|
||||
adjust_arch() {
|
||||
# adjust archive name based on ARCH
|
||||
true
|
||||
}
|
||||
|
||||
cat /dev/null <<EOF
|
||||
------------------------------------------------------------------------
|
||||
https://github.com/client9/shlib - portable posix shell functions
|
||||
Public domain - http://unlicense.org
|
||||
https://github.com/client9/shlib/blob/master/LICENSE.md
|
||||
but credit (and pull requests) appreciated.
|
||||
------------------------------------------------------------------------
|
||||
EOF
|
||||
is_command() {
|
||||
command -v "$1" >/dev/null
|
||||
}
|
||||
echoerr() {
|
||||
echo "$@" 1>&2
|
||||
}
|
||||
log_prefix() {
|
||||
echo "$0"
|
||||
}
|
||||
_logp=6
|
||||
log_set_priority() {
|
||||
_logp="$1"
|
||||
}
|
||||
log_priority() {
|
||||
if test -z "$1"; then
|
||||
echo "$_logp"
|
||||
return
|
||||
fi
|
||||
[ "$1" -le "$_logp" ]
|
||||
}
|
||||
log_tag() {
|
||||
case $1 in
|
||||
0) echo "emerg" ;;
|
||||
1) echo "alert" ;;
|
||||
2) echo "crit" ;;
|
||||
3) echo "err" ;;
|
||||
4) echo "warning" ;;
|
||||
5) echo "notice" ;;
|
||||
6) echo "info" ;;
|
||||
7) echo "debug" ;;
|
||||
*) echo "$1" ;;
|
||||
esac
|
||||
}
|
||||
log_debug() {
|
||||
log_priority 7 || return 0
|
||||
echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
|
||||
}
|
||||
log_info() {
|
||||
log_priority 6 || return 0
|
||||
echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
|
||||
}
|
||||
log_err() {
|
||||
log_priority 3 || return 0
|
||||
echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
|
||||
}
|
||||
log_crit() {
|
||||
log_priority 2 || return 0
|
||||
echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
|
||||
}
|
||||
uname_os() {
|
||||
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
case "$os" in
|
||||
cygwin_nt*) os="windows" ;;
|
||||
mingw*) os="windows" ;;
|
||||
msys_nt*) os="windows" ;;
|
||||
esac
|
||||
echo "$os"
|
||||
}
|
||||
uname_arch() {
|
||||
arch=$(uname -m)
|
||||
case $arch in
|
||||
x86_64) arch="amd64" ;;
|
||||
x86) arch="386" ;;
|
||||
i686) arch="386" ;;
|
||||
i386) arch="386" ;;
|
||||
aarch64) arch="arm64" ;;
|
||||
armv5*) arch="armv5" ;;
|
||||
armv6*) arch="armv6" ;;
|
||||
armv7*) arch="armv7" ;;
|
||||
esac
|
||||
echo ${arch}
|
||||
}
|
||||
uname_os_check() {
|
||||
os=$(uname_os)
|
||||
case "$os" in
|
||||
darwin) return 0 ;;
|
||||
dragonfly) return 0 ;;
|
||||
freebsd) return 0 ;;
|
||||
linux) return 0 ;;
|
||||
android) return 0 ;;
|
||||
nacl) return 0 ;;
|
||||
netbsd) return 0 ;;
|
||||
openbsd) return 0 ;;
|
||||
plan9) return 0 ;;
|
||||
solaris) return 0 ;;
|
||||
windows) return 0 ;;
|
||||
esac
|
||||
log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
|
||||
return 1
|
||||
}
|
||||
uname_arch_check() {
|
||||
arch=$(uname_arch)
|
||||
case "$arch" in
|
||||
386) return 0 ;;
|
||||
amd64) return 0 ;;
|
||||
arm64) return 0 ;;
|
||||
armv5) return 0 ;;
|
||||
armv6) return 0 ;;
|
||||
armv7) return 0 ;;
|
||||
ppc64) return 0 ;;
|
||||
ppc64le) return 0 ;;
|
||||
mips) return 0 ;;
|
||||
mipsle) return 0 ;;
|
||||
mips64) return 0 ;;
|
||||
mips64le) return 0 ;;
|
||||
s390x) return 0 ;;
|
||||
amd64p32) return 0 ;;
|
||||
esac
|
||||
log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
|
||||
return 1
|
||||
}
|
||||
untar() {
|
||||
tarball=$1
|
||||
case "${tarball}" in
|
||||
*.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;;
|
||||
*.tar) tar --no-same-owner -xf "${tarball}" ;;
|
||||
*.zip) unzip "${tarball}" ;;
|
||||
*)
|
||||
log_err "untar unknown archive format for ${tarball}"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
http_download_curl() {
|
||||
local_file=$1
|
||||
source_url=$2
|
||||
header=$3
|
||||
if [ -z "$header" ]; then
|
||||
code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
|
||||
else
|
||||
code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
|
||||
fi
|
||||
if [ "$code" != "200" ]; then
|
||||
log_debug "http_download_curl received HTTP status $code"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
http_download_wget() {
|
||||
local_file=$1
|
||||
source_url=$2
|
||||
header=$3
|
||||
if [ -z "$header" ]; then
|
||||
wget -q -O "$local_file" "$source_url"
|
||||
else
|
||||
wget -q --header "$header" -O "$local_file" "$source_url"
|
||||
fi
|
||||
}
|
||||
http_download() {
|
||||
log_debug "http_download $2"
|
||||
if is_command curl; then
|
||||
http_download_curl "$@"
|
||||
return
|
||||
elif is_command wget; then
|
||||
http_download_wget "$@"
|
||||
return
|
||||
fi
|
||||
log_crit "http_download unable to find wget or curl"
|
||||
return 1
|
||||
}
|
||||
http_copy() {
|
||||
tmp=$(mktemp)
|
||||
http_download "${tmp}" "$1" "$2" || return 1
|
||||
body=$(cat "$tmp")
|
||||
rm -f "${tmp}"
|
||||
echo "$body"
|
||||
}
|
||||
github_release() {
|
||||
owner_repo=$1
|
||||
version=$2
|
||||
test -z "$version" && version="latest"
|
||||
giturl="https://github.com/${owner_repo}/releases/${version}"
|
||||
json=$(http_copy "$giturl" "Accept:application/json")
|
||||
test -z "$json" && return 1
|
||||
version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
|
||||
test -z "$version" && return 1
|
||||
echo "$version"
|
||||
}
|
||||
hash_sha256() {
|
||||
TARGET=${1:-/dev/stdin}
|
||||
if is_command gsha256sum; then
|
||||
hash=$(gsha256sum "$TARGET") || return 1
|
||||
echo "$hash" | cut -d ' ' -f 1
|
||||
elif is_command sha256sum; then
|
||||
hash=$(sha256sum "$TARGET") || return 1
|
||||
echo "$hash" | cut -d ' ' -f 1
|
||||
elif is_command shasum; then
|
||||
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
|
||||
echo "$hash" | cut -d ' ' -f 1
|
||||
elif is_command openssl; then
|
||||
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
|
||||
echo "$hash" | cut -d ' ' -f a
|
||||
else
|
||||
log_crit "hash_sha256 unable to find command to compute sha-256 hash"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
hash_sha256_verify() {
|
||||
TARGET=$1
|
||||
checksums=$2
|
||||
if [ -z "$checksums" ]; then
|
||||
log_err "hash_sha256_verify checksum file not specified in arg2"
|
||||
return 1
|
||||
fi
|
||||
BASENAME=${TARGET##*/}
|
||||
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
|
||||
if [ -z "$want" ]; then
|
||||
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
|
||||
return 1
|
||||
fi
|
||||
got=$(hash_sha256 "$TARGET")
|
||||
if [ "$want" != "$got" ]; then
|
||||
log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
cat /dev/null <<EOF
|
||||
------------------------------------------------------------------------
|
||||
End of functions from https://github.com/client9/shlib
|
||||
------------------------------------------------------------------------
|
||||
EOF
|
||||
|
||||
PROJECT_NAME="golangci-lint"
|
||||
OWNER=golangci
|
||||
REPO="golangci-lint"
|
||||
BINARY=golangci-lint
|
||||
FORMAT=tar.gz
|
||||
OS=$(uname_os)
|
||||
ARCH=$(uname_arch)
|
||||
PREFIX="$OWNER/$REPO"
|
||||
|
||||
# use in logging routines
|
||||
log_prefix() {
|
||||
echo "$PREFIX"
|
||||
}
|
||||
PLATFORM="${OS}/${ARCH}"
|
||||
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
|
||||
|
||||
uname_os_check "$OS"
|
||||
uname_arch_check "$ARCH"
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
get_binaries
|
||||
|
||||
tag_to_version
|
||||
|
||||
adjust_format
|
||||
|
||||
adjust_os
|
||||
|
||||
adjust_arch
|
||||
|
||||
log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
|
||||
|
||||
NAME=${BINARY}-${VERSION}-${OS}-${ARCH}
|
||||
TARBALL=${NAME}.${FORMAT}
|
||||
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
|
||||
CHECKSUM=${PROJECT_NAME}-${VERSION}-checksums.txt
|
||||
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
|
||||
|
||||
|
||||
execute
|
||||
|
|
@ -24,22 +24,18 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/klog/v2/klogr"
|
||||
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
|
||||
"sigs.k8s.io/cluster-api/controllers/remote"
|
||||
"sigs.k8s.io/cluster-api/util/record"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
// to ensure that exec-entrypoint and run can make use of them.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
|
||||
infrav1 "github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/api/v1beta1"
|
||||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/controllers"
|
||||
|
|
@ -111,6 +107,10 @@ func main() {
|
|||
Indexes: remote.DefaultIndexes,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create cluster cache tracker")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Initialize event recorder.
|
||||
record.InitFromRecorder(mgr.GetEventRecorderFor("kk-controller"))
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
|
|
@ -41,26 +40,29 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// Default values.
|
||||
const (
|
||||
DefaultSSHPort = 22
|
||||
DefaultTimeout = 15
|
||||
)
|
||||
|
||||
// Client is a wrapper around the SSH client that provides a few helper.
|
||||
type Client struct {
|
||||
logr.Logger
|
||||
mu sync.Mutex
|
||||
User string
|
||||
Password string
|
||||
Port *int
|
||||
PrivateKey string
|
||||
PrivateKeyPath string
|
||||
Timeout *time.Duration
|
||||
user string
|
||||
password string
|
||||
port *int
|
||||
privateKey string
|
||||
privateKeyPath string
|
||||
timeout *time.Duration
|
||||
host string
|
||||
sshClient *ssh.Client
|
||||
sftpClient *sftp.Client
|
||||
fs filesystem.Interface
|
||||
}
|
||||
|
||||
// NewClient returns a new client given ssh information.
|
||||
func NewClient(host string, auth infrav1.Auth, log *logr.Logger) Interface {
|
||||
if log == nil {
|
||||
l := klogr.New()
|
||||
|
|
@ -70,45 +72,46 @@ func NewClient(host string, auth infrav1.Auth, log *logr.Logger) Interface {
|
|||
auth.User = "root"
|
||||
}
|
||||
|
||||
var port int
|
||||
port = DefaultSSHPort
|
||||
port := DefaultSSHPort
|
||||
if auth.Port == nil {
|
||||
auth.Port = &port
|
||||
}
|
||||
|
||||
var timeout time.Duration
|
||||
timeout = time.Duration(DefaultTimeout) * time.Second
|
||||
timeout := time.Duration(DefaultTimeout) * time.Second
|
||||
if auth.Timeout == nil {
|
||||
auth.Timeout = &timeout
|
||||
}
|
||||
|
||||
return &Client{
|
||||
User: auth.User,
|
||||
Password: auth.Password,
|
||||
Port: auth.Port,
|
||||
PrivateKey: auth.PrivateKey,
|
||||
PrivateKeyPath: auth.PrivateKeyPath,
|
||||
Timeout: auth.Timeout,
|
||||
user: auth.User,
|
||||
password: auth.Password,
|
||||
port: auth.Port,
|
||||
privateKey: auth.PrivateKey,
|
||||
privateKeyPath: auth.PrivateKeyPath,
|
||||
timeout: auth.Timeout,
|
||||
host: host,
|
||||
fs: filesystem.NewFileSystem(),
|
||||
Logger: *log,
|
||||
}
|
||||
}
|
||||
|
||||
// Connect connects to the host using the provided ssh information.
|
||||
func (c *Client) Connect() error {
|
||||
authMethods, err := c.authMethod(c.Password, c.PrivateKey, c.PrivateKeyPath)
|
||||
authMethods, err := c.authMethod(c.password, c.privateKey, c.privateKeyPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "The given SSH key could not be parsed")
|
||||
}
|
||||
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: c.User,
|
||||
Timeout: *c.Timeout,
|
||||
Auth: authMethods,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
User: c.user,
|
||||
Timeout: *c.timeout,
|
||||
Auth: authMethods,
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
endpoint := net.JoinHostPort(c.host, strconv.Itoa(*c.Port))
|
||||
endpoint := net.JoinHostPort(c.host, strconv.Itoa(*c.port))
|
||||
sshClient, err := ssh.Dial("tcp", endpoint, sshConfig)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not establish connection to %s", endpoint)
|
||||
|
|
@ -118,6 +121,7 @@ func (c *Client) Connect() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ConnectSftpClient connects to the host sftp client using the provided ssh information.
|
||||
func (c *Client) ConnectSftpClient(opts ...sftp.ClientOption) error {
|
||||
sess1, err := c.sshClient.NewSession()
|
||||
if err != nil {
|
||||
|
|
@ -163,6 +167,7 @@ func (c *Client) ConnectSftpClient(opts ...sftp.ClientOption) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Close closes the underlying ssh and sftp connection.
|
||||
func (c *Client) Close() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
|
@ -199,7 +204,7 @@ func (c *Client) privateKeyMethod(privateKey, privateKeyPath string) (am ssh.Aut
|
|||
var signer ssh.Signer
|
||||
|
||||
if fileExist(privateKeyPath) {
|
||||
content, err := ioutil.ReadFile(filepath.Clean(privateKeyPath))
|
||||
content, err := os.ReadFile(filepath.Clean(privateKeyPath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -252,6 +257,7 @@ func (c *Client) session() (*ssh.Session, error) {
|
|||
return sess, nil
|
||||
}
|
||||
|
||||
// Cmd executes a command on the remote host.
|
||||
func (c *Client) Cmd(cmd string) (string, error) {
|
||||
if err := c.Connect(); err != nil {
|
||||
return "", errors.Wrapf(err, "[%s] connect ssh client failed", c.host)
|
||||
|
|
@ -273,10 +279,12 @@ func (c *Client) Cmd(cmd string) (string, error) {
|
|||
return string(output), nil
|
||||
}
|
||||
|
||||
// Cmdf execute a formatting command according to the format specifier.
|
||||
func (c *Client) Cmdf(cmd string, a ...any) (string, error) {
|
||||
return c.Cmd(fmt.Sprintf(cmd, a...))
|
||||
}
|
||||
|
||||
// SudoCmd executes a command on the remote host with sudo.
|
||||
func (c *Client) SudoCmd(cmd string) (string, error) {
|
||||
if err := c.Connect(); err != nil {
|
||||
return "", errors.Wrapf(err, "[%s] connect ssh client failed", c.host)
|
||||
|
|
@ -330,14 +338,14 @@ func (c *Client) sudoCmd(cmd string) (string, error) {
|
|||
line += string(b)
|
||||
|
||||
if (strings.HasPrefix(line, "[sudo] password for ") || strings.HasPrefix(line, "Password")) && strings.HasSuffix(line, ": ") {
|
||||
_, err = in.Write([]byte(c.Password + "\n"))
|
||||
_, err = in.Write([]byte(c.password + "\n"))
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outStr := strings.TrimPrefix(string(output), fmt.Sprintf("[sudo] password for %s:", c.User))
|
||||
outStr := strings.TrimPrefix(string(output), fmt.Sprintf("[sudo] password for %s:", c.user))
|
||||
err = session.Wait()
|
||||
if err != nil {
|
||||
return strings.TrimSpace(outStr), errors.Wrap(err, strings.TrimSpace(outStr))
|
||||
|
|
@ -345,10 +353,12 @@ func (c *Client) sudoCmd(cmd string) (string, error) {
|
|||
return strings.TrimSpace(outStr), nil
|
||||
}
|
||||
|
||||
// SudoCmdf executes a formatting command on the remote host with sudo.
|
||||
func (c *Client) SudoCmdf(cmd string, a ...any) (string, error) {
|
||||
return c.SudoCmd(fmt.Sprintf(cmd, a...))
|
||||
}
|
||||
|
||||
// Copy copies a file to the remote host.
|
||||
func (c *Client) Copy(src, dst string) error {
|
||||
if err := c.Connect(); err != nil {
|
||||
return errors.Wrapf(err, "[%s] connect ssh client failed", c.host)
|
||||
|
|
@ -360,6 +370,7 @@ func (c *Client) Copy(src, dst string) error {
|
|||
defer c.sshClient.Close()
|
||||
defer c.sftpClient.Close()
|
||||
|
||||
src = filepath.Clean(src)
|
||||
f, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "[%s] get file stat failed", c.host)
|
||||
|
|
@ -399,7 +410,7 @@ func (c *Client) copyLocalFileToRemote(src, dst string) error {
|
|||
}
|
||||
}
|
||||
|
||||
srcFile, err := os.Open(src)
|
||||
srcFile, err := os.Open(filepath.Clean(src))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -428,6 +439,7 @@ func (c *Client) copyLocalFileToRemote(src, dst string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Fetch fetches a file from the remote host.
|
||||
func (c *Client) Fetch(local, remote string) error {
|
||||
if err := c.Connect(); err != nil {
|
||||
return errors.Wrapf(err, "[%s] connect ssh client failed", c.host)
|
||||
|
|
@ -487,6 +499,7 @@ func (c *Client) remoteMd5Sum(dst string) string {
|
|||
return remoteMd5
|
||||
}
|
||||
|
||||
// RemoteFileExist checks if a file exists on the remote host.
|
||||
func (c *Client) RemoteFileExist(remote string) (bool, error) {
|
||||
if err := c.Connect(); err != nil {
|
||||
return false, errors.Wrapf(err, "[%s] connect failed", c.host)
|
||||
|
|
@ -512,6 +525,7 @@ func (c *Client) remoteFileExist(remote string) (bool, error) {
|
|||
return count != 0, nil
|
||||
}
|
||||
|
||||
// Ping checks if the remote host is reachable.
|
||||
func (c *Client) Ping() error {
|
||||
if err := c.Connect(); err != nil {
|
||||
return errors.Wrapf(err, "[%s] connect failed", c.host)
|
||||
|
|
@ -520,10 +534,12 @@ func (c *Client) Ping() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Host returns the host name of the ssh client.
|
||||
func (c *Client) Host() string {
|
||||
return c.host
|
||||
}
|
||||
|
||||
// Fs returns the filesystem of the ssh client.
|
||||
func (c *Client) Fs() filesystem.Interface {
|
||||
return c.fs
|
||||
}
|
||||
|
|
@ -533,6 +549,7 @@ func fileExist(path string) bool {
|
|||
return err == nil || os.IsExist(err)
|
||||
}
|
||||
|
||||
// SudoPrefix returns the prefix for sudo commands.
|
||||
func SudoPrefix(cmd string) string {
|
||||
return fmt.Sprintf("sudo -E /bin/bash <<EOF\n%s\nEOF", cmd)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 ssh
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Dialer struct {
|
||||
lock sync.Mutex
|
||||
clients map[string]Interface
|
||||
}
|
||||
|
||||
func NewDialer() *Dialer {
|
||||
return &Dialer{
|
||||
clients: make(map[string]Interface),
|
||||
}
|
||||
}
|
||||
|
||||
//func (d *Dialer) Ping(host string, auth *infrav1.Auth, retry int) error {
|
||||
// d.lock.Lock()
|
||||
// defer d.lock.Unlock()
|
||||
//
|
||||
// var err error
|
||||
// client := NewClient(host, auth)
|
||||
// for i := 0; i < retry; i++ {
|
||||
// err = client.Ping()
|
||||
// if err == nil {
|
||||
// break
|
||||
// }
|
||||
// time.Sleep(time.Duration(i) * time.Second)
|
||||
// }
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
//func (d *Dialer) Connect(host string, auth *infrav1.Auth) (Interface, error) {
|
||||
// d.lock.Lock()
|
||||
// defer d.lock.Unlock()
|
||||
//
|
||||
// client, ok := d.clients[host]
|
||||
// if !ok {
|
||||
// client = NewClient(host, auth)
|
||||
// if err := client.Connect(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// d.clients[host] = client
|
||||
// }
|
||||
//
|
||||
// return client, nil
|
||||
//}
|
||||
|
||||
func (d *Dialer) Close(host string) {
|
||||
client, ok := d.clients[host]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
client.Close()
|
||||
|
||||
c := client.(*Client)
|
||||
d.forgetClient(c)
|
||||
}
|
||||
|
||||
func (d *Dialer) forgetClient(client *Client) {
|
||||
d.lock.Lock()
|
||||
defer d.lock.Unlock()
|
||||
|
||||
for k := range d.clients {
|
||||
if d.clients[k] == client {
|
||||
delete(d.clients, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 ssh implements the ssh client.
|
||||
package ssh
|
||||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// Interface is the interface for ssh client.
|
||||
type Interface interface {
|
||||
Connector
|
||||
Command
|
||||
|
|
@ -29,11 +30,13 @@ type Interface interface {
|
|||
Host() string
|
||||
}
|
||||
|
||||
// Connector collects the methods for connecting and closing.
|
||||
type Connector interface {
|
||||
Connect() error
|
||||
Close()
|
||||
}
|
||||
|
||||
// Command collects the methods for executing commands.
|
||||
type Command interface {
|
||||
Cmd(cmd string) (string, error)
|
||||
Cmdf(cmd string, a ...any) (string, error)
|
||||
|
|
@ -41,12 +44,14 @@ type Command interface {
|
|||
SudoCmdf(cmd string, a ...any) (string, error)
|
||||
}
|
||||
|
||||
// Sftp collects the methods for sftp.
|
||||
type Sftp interface {
|
||||
Copy(local, remote string) error
|
||||
Fetch(local, remote string) error
|
||||
RemoteFileExist(remote string) (bool, error)
|
||||
}
|
||||
|
||||
// LocalFileSystem collects the methods for return a local filesystem.
|
||||
type LocalFileSystem interface {
|
||||
Fs() filesystem.Interface
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package pkg defines the interface for a cluster scope.
|
||||
package pkg
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package rootfs
|
||||
|
||||
// common dir.
|
||||
const (
|
||||
DefaultLocalTmpDir = "/var/lib/kubekey"
|
||||
DefaultLocalRootFsDir = "/var/lib/kubekey/rootfs"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 rootfs defines the CAPKK rootfs.
|
||||
package rootfs
|
||||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// Interface is the interface for rootfs.
|
||||
type Interface interface {
|
||||
// ClusterRootFsDir returns the rootfs directory of the cluster.
|
||||
ClusterRootFsDir() string
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// Local is a rootfs for local.
|
||||
type Local struct {
|
||||
clusterName string
|
||||
basePath string
|
||||
fs filesystem.Interface
|
||||
}
|
||||
|
||||
// NewLocalRootFs returns a new Local implementation of rootfs interface.
|
||||
func NewLocalRootFs(clusterName, basePath string) Interface {
|
||||
if basePath == "" {
|
||||
basePath = DefaultLocalRootFsDir
|
||||
|
|
@ -39,14 +41,17 @@ func NewLocalRootFs(clusterName, basePath string) Interface {
|
|||
}
|
||||
}
|
||||
|
||||
// ClusterRootFsDir returns the rootfs directory for the cluster.
|
||||
func (l *Local) ClusterRootFsDir() string {
|
||||
return filepath.Join(l.basePath, l.clusterName)
|
||||
}
|
||||
|
||||
// HostRootFsDir returns the rootfs directory for the host.
|
||||
func (l *Local) HostRootFsDir(host string) string {
|
||||
return filepath.Join(l.basePath, l.clusterName, host)
|
||||
}
|
||||
|
||||
// Fs returns the filesystem interface.
|
||||
func (l *Local) Fs() filesystem.Interface {
|
||||
return l.fs
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,26 +111,32 @@ func (s *ClusterScope) KubernetesClusterName() string {
|
|||
return s.Cluster.Name
|
||||
}
|
||||
|
||||
// ControlPlaneEndpoint returns the control plane endpoint.
|
||||
func (s *ClusterScope) ControlPlaneEndpoint() clusterv1.APIEndpoint {
|
||||
return s.KKCluster.Spec.ControlPlaneEndpoint
|
||||
}
|
||||
|
||||
// GlobalRegistry returns the global registry spec.
|
||||
func (s *ClusterScope) GlobalRegistry() *infrav1.Registry {
|
||||
return &s.KKCluster.Spec.Registry
|
||||
}
|
||||
|
||||
// GlobalAuth returns the global auth spec.
|
||||
func (s *ClusterScope) GlobalAuth() *infrav1.Auth {
|
||||
return &s.KKCluster.Spec.Nodes.Auth
|
||||
}
|
||||
|
||||
// GlobalContainerManager returns the global container manager spec.
|
||||
func (s *ClusterScope) GlobalContainerManager() *infrav1.ContainerManager {
|
||||
return &s.KKCluster.Spec.Nodes.ContainerManager
|
||||
}
|
||||
|
||||
// AllInstancesSpec returns the all KKInstance specs.
|
||||
func (s *ClusterScope) AllInstancesSpec() []infrav1.KKInstanceSpec {
|
||||
return s.KKCluster.Spec.Nodes.Instances
|
||||
}
|
||||
|
||||
// GetInstancesSpecByRole returns the KKInstance spec for the given role.
|
||||
func (s *ClusterScope) GetInstancesSpecByRole(role infrav1.Role) []infrav1.KKInstanceSpec {
|
||||
var arr []infrav1.KKInstanceSpec
|
||||
for _, v := range s.KKCluster.Spec.Nodes.Instances {
|
||||
|
|
@ -143,6 +149,7 @@ func (s *ClusterScope) GetInstancesSpecByRole(role infrav1.Role) []infrav1.KKIns
|
|||
return arr
|
||||
}
|
||||
|
||||
// AllInstances returns all existing KKInstances in the cluster.
|
||||
func (s *ClusterScope) AllInstances() ([]*infrav1.KKInstance, error) {
|
||||
// Get all KKInstances linked to this KKCluster.
|
||||
allInstances := &infrav1.KKInstanceList{}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 scope defines the basic context for an actuator to operate upon.
|
||||
package scope
|
||||
|
|
@ -50,9 +50,6 @@ func NewInstanceScope(params InstanceScopeParams) (*InstanceScope, error) {
|
|||
if params.Client == nil {
|
||||
return nil, errors.New("client is required when creating a InstanceScope")
|
||||
}
|
||||
//if params.Machine == nil {
|
||||
// return nil, errors.New("machine is required when creating a InstanceScope")
|
||||
//}
|
||||
if params.Cluster == nil {
|
||||
return nil, errors.New("cluster is required when creating a InstanceScope")
|
||||
}
|
||||
|
|
@ -102,34 +99,42 @@ type InstanceScope struct {
|
|||
KKInstance *infrav1.KKInstance
|
||||
}
|
||||
|
||||
// Name returns the name of the KKInstance.
|
||||
func (i *InstanceScope) Name() string {
|
||||
return i.KKInstance.Name
|
||||
}
|
||||
|
||||
// HostName returns the hostname of the KKInstance corresponding remote host.
|
||||
func (i *InstanceScope) HostName() string {
|
||||
return i.KKInstance.Spec.Name
|
||||
}
|
||||
|
||||
// Namespace returns the namespace of the KKInstance.
|
||||
func (i *InstanceScope) Namespace() string {
|
||||
return i.KKInstance.Namespace
|
||||
}
|
||||
|
||||
// InternalAddress returns the internal address of the KKInstance.
|
||||
func (i *InstanceScope) InternalAddress() string {
|
||||
return i.KKInstance.Spec.InternalAddress
|
||||
}
|
||||
|
||||
// Arch returns the architecture of the KKInstance.
|
||||
func (i *InstanceScope) Arch() string {
|
||||
return i.KKInstance.Spec.Arch
|
||||
}
|
||||
|
||||
// ContainerManager returns the ContainerManager struct of the KKInstance.
|
||||
func (i *InstanceScope) ContainerManager() *infrav1.ContainerManager {
|
||||
return &i.KKInstance.Spec.ContainerManager
|
||||
}
|
||||
|
||||
// KubernetesVersion returns the Kubernetes version of the KKInstance.
|
||||
func (i *InstanceScope) KubernetesVersion() string {
|
||||
return *i.Machine.Spec.Version
|
||||
}
|
||||
|
||||
// GetRawBootstrapDataWithFormat returns the raw bootstrap data from the corresponding machine.spec.bootstrap.
|
||||
func (i *InstanceScope) GetRawBootstrapDataWithFormat(ctx context.Context) ([]byte, bootstrapv1.Format, error) {
|
||||
if i.Machine.Spec.Bootstrap.DataSecretName == nil {
|
||||
return nil, "", errors.New("error retrieving bootstrap data: linked Machine's bootstrap.dataSecretName is nil")
|
||||
|
|
@ -194,6 +199,7 @@ func (i *InstanceScope) HasFailed() bool {
|
|||
return i.KKInstance.Status.FailureReason != nil || i.KKInstance.Status.FailureMessage != nil
|
||||
}
|
||||
|
||||
// SetState sets the state of the KKInstance.
|
||||
func (i *InstanceScope) SetState(state infrav1.InstanceState) {
|
||||
i.KKInstance.Status.State = state
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg"
|
||||
)
|
||||
|
||||
// KKInstanceScope is a scope for global KKInstance.
|
||||
type KKInstanceScope interface {
|
||||
pkg.ClusterScoper
|
||||
// GlobalAuth returns the global auth configuration of all instances.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg"
|
||||
)
|
||||
|
||||
// LBScope is a scope for LB.
|
||||
type LBScope interface {
|
||||
pkg.ClusterScoper
|
||||
// ControlPlaneEndpoint returns KKCluster control plane endpoint
|
||||
|
|
|
|||
|
|
@ -145,10 +145,12 @@ func (m *MachineScope) SetAddresses(addrs []clusterv1.MachineAddress) {
|
|||
m.KKMachine.Status.Addresses = addrs
|
||||
}
|
||||
|
||||
// GetRoles returns the KKMachine roles.
|
||||
func (m *MachineScope) GetRoles() []infrav1.Role {
|
||||
return m.KKMachine.Spec.Roles
|
||||
}
|
||||
|
||||
// IsRole returns true if the machine has the given role.
|
||||
func (m *MachineScope) IsRole(role infrav1.Role) bool {
|
||||
for _, r := range m.KKMachine.Spec.Roles {
|
||||
if r == role {
|
||||
|
|
@ -196,10 +198,6 @@ func (m *MachineScope) PatchObject() error {
|
|||
infrav1.InstanceReadyCondition,
|
||||
}
|
||||
|
||||
if m.IsControlPlane() {
|
||||
//applicableConditions = append(applicableConditions, infrav1.ELBAttachedCondition)
|
||||
}
|
||||
|
||||
conditions.SetSummary(m.KKMachine,
|
||||
conditions.WithConditions(applicableConditions...),
|
||||
conditions.WithStepCounterIf(m.KKMachine.ObjectMeta.DeletionTimestamp.IsZero()),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
infrav1 "github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/api/v1beta1"
|
||||
)
|
||||
|
||||
// RegistryScope is the scope for global registry.
|
||||
type RegistryScope interface {
|
||||
Registry() *infrav1.Registry
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
//go:embed templates
|
||||
var f embed.FS
|
||||
|
||||
// DownloadAll downloads all binaries.
|
||||
func (s *Service) DownloadAll(timeout time.Duration) error {
|
||||
kubeadm, err := s.getKubeadmService(s.SSHClient, s.instanceScope.KubernetesVersion(), s.instanceScope.Arch())
|
||||
if err != nil {
|
||||
|
|
@ -62,7 +63,7 @@ func (s *Service) DownloadAll(timeout time.Duration) error {
|
|||
}
|
||||
if needGet {
|
||||
s.instanceScope.V(4).Info("download binary", "binary", b.Name(),
|
||||
"version", b.Version(), "url", b.Url())
|
||||
"version", b.Version(), "url", b.URL())
|
||||
if err := b.Get(timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -85,6 +86,7 @@ func (s *Service) DownloadAll(timeout time.Duration) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ConfigureKubelet configures kubelet.
|
||||
func (s *Service) ConfigureKubelet() error {
|
||||
kubelet, err := s.getKubeletService(s.SSHClient, s.instanceScope.KubernetesVersion(), s.instanceScope.Arch())
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 binary define the binaries operations on the remote instance.
|
||||
package binary
|
||||
|
|
@ -25,6 +25,8 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file"
|
||||
)
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service struct {
|
||||
SSHClient ssh.Interface
|
||||
scope scope.KKInstanceScope
|
||||
|
|
@ -37,6 +39,7 @@ type Service struct {
|
|||
kubectlFactory func(sshClient ssh.Interface, version, arch string) (operation.Binary, error)
|
||||
}
|
||||
|
||||
// NewService returns a new service given the remote instance.
|
||||
func NewService(sshClient ssh.Interface, scope scope.KKInstanceScope, instanceScope *scope.InstanceScope) *Service {
|
||||
return &Service{
|
||||
SSHClient: sshClient,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import (
|
|||
//go:embed templates
|
||||
var f embed.FS
|
||||
|
||||
// AddUsers adds a kube user to the Linux.
|
||||
func (s *Service) AddUsers() error {
|
||||
userService := s.getUserService("kube", "Kubernetes user")
|
||||
|
||||
|
|
@ -42,8 +43,9 @@ func (s *Service) AddUsers() error {
|
|||
return userService.Add()
|
||||
}
|
||||
|
||||
// SetHostname sets the hostname of the machine.
|
||||
func (s *Service) SetHostname() error {
|
||||
if _, err := s.SSHClient.SudoCmdf(
|
||||
if _, err := s.sshClient.SudoCmdf(
|
||||
"hostnamectl set-hostname %s && sed -i '/^127.0.1.1/s/.*/127.0.1.1 %s/g' /etc/hosts",
|
||||
s.instanceScope.HostName(),
|
||||
s.instanceScope.HostName()); err != nil {
|
||||
|
|
@ -52,6 +54,7 @@ func (s *Service) SetHostname() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CreateDirectory creates some common directories.
|
||||
func (s *Service) CreateDirectory() error {
|
||||
makeDirs := []string{
|
||||
directory.BinDir,
|
||||
|
|
@ -90,6 +93,7 @@ func (s *Service) CreateDirectory() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ResetTmpDirectory resets the temporary "/tmp/kubekey" directory.
|
||||
func (s *Service) ResetTmpDirectory() error {
|
||||
dirService := s.getDirectoryService(directory.TmpDir, os.FileMode(filesystem.FileMode0755))
|
||||
if err := dirService.Remove(); err != nil {
|
||||
|
|
@ -101,15 +105,13 @@ func (s *Service) ResetTmpDirectory() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ExecInitScript executes the init script on the remote instance.
|
||||
func (s *Service) ExecInitScript() error {
|
||||
var (
|
||||
hostsList []string
|
||||
lbHost string
|
||||
)
|
||||
|
||||
//if s.scope.ControlPlaneLoadBalancer().Address != "" {
|
||||
// lbHost = fmt.Sprintf("%s %s", s.scope.ControlPlaneLoadBalancer().Address, s.scope.ControlPlaneEndpoint().Host)
|
||||
//}
|
||||
for _, host := range s.scope.AllInstancesSpec() {
|
||||
if host.Name != "" {
|
||||
hostsList = append(hostsList, fmt.Sprintf("%s %s.%s %s",
|
||||
|
|
@ -144,14 +146,18 @@ func (s *Service) ExecInitScript() error {
|
|||
if err := svc.Chmod("+x"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := s.SSHClient.SudoCmd(svc.RemotePath()); err != nil {
|
||||
if _, err := s.sshClient.SudoCmd(svc.RemotePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Repository updates the linux package manager and installs some tools.
|
||||
// Ex:
|
||||
// apt-get update && apt-get install -y socat conntrack ipset ebtables chrony ipvsadm
|
||||
// yum clean all && yum makecache && yum install -y openssl socat conntrack ipset ebtables chrony ipvsadm
|
||||
func (s *Service) Repository() error {
|
||||
output, err := s.SSHClient.SudoCmd("cat /etc/os-release")
|
||||
output, err := s.sshClient.SudoCmd("cat /etc/os-release")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get os release")
|
||||
}
|
||||
|
|
@ -167,6 +173,7 @@ func (s *Service) Repository() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ResetNetwork resets the network configuration.
|
||||
func (s *Service) ResetNetwork() error {
|
||||
networkResetCmds := []string{
|
||||
"iptables -F",
|
||||
|
|
@ -178,11 +185,12 @@ func (s *Service) ResetNetwork() error {
|
|||
"ip link del nodelocaldns",
|
||||
}
|
||||
for _, cmd := range networkResetCmds {
|
||||
_, _ = s.SSHClient.SudoCmd(cmd)
|
||||
_, _ = s.sshClient.SudoCmd(cmd)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveFiles removes some directories and files that may have been created by the Kubernetes and other related components.
|
||||
func (s *Service) RemoveFiles() error {
|
||||
removeDirs := []string{
|
||||
directory.KubeConfigDir,
|
||||
|
|
@ -211,8 +219,9 @@ func (s *Service) RemoveFiles() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// DaemonReload reloads the systemd daemon and restart the containerd.
|
||||
func (s *Service) DaemonReload() error {
|
||||
_, _ = s.SSHClient.SudoCmd("systemctl daemon-reload && exit 0")
|
||||
_, _ = s.SSHClient.SudoCmd("systemctl restart containerd")
|
||||
_, _ = s.sshClient.SudoCmd("systemctl daemon-reload && exit 0")
|
||||
_, _ = s.sshClient.SudoCmd("systemctl restart containerd")
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 bootstrap defines the CAPKK bootstrap operations on the remote instance.
|
||||
package bootstrap
|
||||
|
|
@ -29,8 +29,10 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/user"
|
||||
)
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service struct {
|
||||
SSHClient ssh.Interface
|
||||
sshClient ssh.Interface
|
||||
scope scope.LBScope
|
||||
instanceScope *scope.InstanceScope
|
||||
|
||||
|
|
@ -40,9 +42,10 @@ type Service struct {
|
|||
repositoryFactory func(sshClient ssh.Interface, os string) operation.Repository
|
||||
}
|
||||
|
||||
// NewService returns a new service given the remote instance kubekey build-in bootstrap provision client.
|
||||
func NewService(sshClient ssh.Interface, scope scope.LBScope, instanceScope *scope.InstanceScope) *Service {
|
||||
return &Service{
|
||||
SSHClient: sshClient,
|
||||
sshClient: sshClient,
|
||||
scope: scope,
|
||||
instanceScope: instanceScope,
|
||||
}
|
||||
|
|
@ -50,28 +53,28 @@ func NewService(sshClient ssh.Interface, scope scope.LBScope, instanceScope *sco
|
|||
|
||||
func (s *Service) getUserService(name, desc string) operation.User {
|
||||
if s.userFactory != nil {
|
||||
return s.userFactory(s.SSHClient, name, desc)
|
||||
return s.userFactory(s.sshClient, name, desc)
|
||||
}
|
||||
return user.NewService(s.SSHClient, name, desc)
|
||||
return user.NewService(s.sshClient, name, desc)
|
||||
}
|
||||
|
||||
func (s *Service) getDirectoryService(path string, mode os.FileMode) operation.Directory {
|
||||
if s.directoryFactory != nil {
|
||||
return s.directoryFactory(s.SSHClient, path, mode)
|
||||
return s.directoryFactory(s.sshClient, path, mode)
|
||||
}
|
||||
return directory.NewService(s.SSHClient, path, mode)
|
||||
return directory.NewService(s.sshClient, path, mode)
|
||||
}
|
||||
|
||||
func (s *Service) getTemplateService(template *template.Template, data file.Data, dst string) (operation.Template, error) {
|
||||
if s.templateFactory != nil {
|
||||
return s.templateFactory(s.SSHClient, template, data, dst)
|
||||
return s.templateFactory(s.sshClient, template, data, dst)
|
||||
}
|
||||
return file.NewTemplate(s.SSHClient, s.scope.RootFs(), template, data, dst)
|
||||
return file.NewTemplate(s.sshClient, s.scope.RootFs(), template, data, dst)
|
||||
}
|
||||
|
||||
func (s *Service) getRepositoryService(os string) operation.Repository {
|
||||
if s.repositoryFactory != nil {
|
||||
return s.repositoryFactory(s.SSHClient, os)
|
||||
return s.repositoryFactory(s.sshClient, os)
|
||||
}
|
||||
return repository.NewService(s.SSHClient, os)
|
||||
return repository.NewService(s.sshClient, os)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package containermanager
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -35,8 +34,9 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file"
|
||||
)
|
||||
|
||||
// ContainerdService is a ContainerManager service implementation for containerd.
|
||||
type ContainerdService struct {
|
||||
SSHClient ssh.Interface
|
||||
sshClient ssh.Interface
|
||||
|
||||
scope scope.KKInstanceScope
|
||||
instanceScope *scope.InstanceScope
|
||||
|
|
@ -47,9 +47,10 @@ type ContainerdService struct {
|
|||
crictlFactory func(sshClient ssh.Interface, version, arch string) (operation.Binary, error)
|
||||
}
|
||||
|
||||
// NewContainerdService returns a new ContainerdService given the remote instance container manager client.
|
||||
func NewContainerdService(sshClient ssh.Interface, scope scope.KKInstanceScope, instanceScope *scope.InstanceScope) *ContainerdService {
|
||||
return &ContainerdService{
|
||||
SSHClient: sshClient,
|
||||
sshClient: sshClient,
|
||||
scope: scope,
|
||||
instanceScope: instanceScope,
|
||||
}
|
||||
|
|
@ -78,21 +79,24 @@ func (s *ContainerdService) getCrictlService(sshClient ssh.Interface, version, a
|
|||
|
||||
func (s *ContainerdService) getTemplateService(template *template.Template, data file.Data, dst string) (operation.Template, error) {
|
||||
if s.templateFactory != nil {
|
||||
return s.templateFactory(s.SSHClient, template, data, dst)
|
||||
return s.templateFactory(s.sshClient, template, data, dst)
|
||||
}
|
||||
return file.NewTemplate(s.SSHClient, s.scope.RootFs(), template, data, dst)
|
||||
return file.NewTemplate(s.sshClient, s.scope.RootFs(), template, data, dst)
|
||||
}
|
||||
|
||||
// Type returns the type containerd of the container manager.
|
||||
func (s *ContainerdService) Type() string {
|
||||
return file.ContainerdID
|
||||
}
|
||||
|
||||
// Version returns the version of the container manager.
|
||||
func (s *ContainerdService) Version() string {
|
||||
return s.instanceScope.KKInstance.Spec.ContainerManager.Version
|
||||
}
|
||||
|
||||
// IsExist returns true if the container manager is installed.
|
||||
func (s *ContainerdService) IsExist() bool {
|
||||
res, err := s.SSHClient.SudoCmd(
|
||||
res, err := s.sshClient.SudoCmd(
|
||||
"if [ -z $(which containerd) ] || [ ! -e /run/containerd/containerd.sock ]; " +
|
||||
"then echo 'not exist'; " +
|
||||
"fi")
|
||||
|
|
@ -105,16 +109,17 @@ func (s *ContainerdService) IsExist() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// Get gets the binary of containerd and related components and copy them to the remote instance.
|
||||
func (s *ContainerdService) Get(timeout time.Duration) error {
|
||||
containerd, err := s.getContainerdService(s.SSHClient, s.Version(), s.instanceScope.Arch())
|
||||
containerd, err := s.getContainerdService(s.sshClient, s.Version(), s.instanceScope.Arch())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runc, err := s.getRuncService(s.SSHClient, file.RuncDefaultVersion, s.instanceScope.Arch())
|
||||
runc, err := s.getRuncService(s.sshClient, file.RuncDefaultVersion, s.instanceScope.Arch())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
crictl, err := s.getCrictlService(s.SSHClient, getFirstMajorVersion(s.instanceScope.KubernetesVersion()), s.instanceScope.Arch())
|
||||
crictl, err := s.getCrictlService(s.sshClient, getFirstMajorVersion(s.instanceScope.KubernetesVersion()), s.instanceScope.Arch())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -132,7 +137,7 @@ func (s *ContainerdService) Get(timeout time.Duration) error {
|
|||
}
|
||||
if needGet {
|
||||
s.instanceScope.V(4).Info("download binary", "binary", b.Name(),
|
||||
"version", b.Version(), "url", b.Url())
|
||||
"version", b.Version(), "url", b.URL())
|
||||
if err := b.Get(timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -147,15 +152,16 @@ func (s *ContainerdService) Get(timeout time.Duration) error {
|
|||
|
||||
// /usr/local
|
||||
dir := filepath.Dir(filepath.Dir(containerd.RemotePath()))
|
||||
if _, err := s.SSHClient.SudoCmdf("tar Cxzvf %s %s", dir, containerd.RemotePath()); err != nil {
|
||||
if _, err := s.sshClient.SudoCmdf("tar Cxzvf %s %s", dir, containerd.RemotePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := s.SSHClient.SudoCmdf("tar Cxzvf %s %s", filepath.Dir(crictl.RemotePath()), crictl.RemotePath()); err != nil {
|
||||
if _, err := s.sshClient.SudoCmdf("tar Cxzvf %s %s", filepath.Dir(crictl.RemotePath()), crictl.RemotePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Install installs the container manager and related components.
|
||||
func (s *ContainerdService) Install() error {
|
||||
if err := s.installContainerd(); err != nil {
|
||||
return err
|
||||
|
|
@ -176,7 +182,7 @@ func (s *ContainerdService) installContainerd() error {
|
|||
if err := s.generateContainerdService(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := s.SSHClient.SudoCmd("systemctl daemon-reload && systemctl enable containerd && systemctl start containerd"); err != nil {
|
||||
if _, err := s.sshClient.SudoCmd("systemctl daemon-reload && systemctl enable containerd && systemctl start containerd"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
@ -212,7 +218,8 @@ func (s *ContainerdService) generateContainerdConfig() error {
|
|||
file.Data{
|
||||
"Mirrors": s.mirrors(),
|
||||
"InsecureRegistries": s.insecureRegistry(),
|
||||
//"SandBoxImage": images.GetImage(m.Runtime, m.KubeConf, "pause").ImageName(),
|
||||
// todo: handle sandbox image
|
||||
// "SandBoxImage": images.GetImage(m.Runtime, m.KubeConf, "pause").ImageName(),
|
||||
"PrivateRegistry": s.privateRegistry(),
|
||||
"Auth": s.auth(),
|
||||
},
|
||||
|
|
@ -234,7 +241,7 @@ func (s *ContainerdService) mirrors() string {
|
|||
if s.scope.GlobalRegistry() != nil {
|
||||
var mirrorsArr []string
|
||||
for _, mirror := range s.scope.GlobalRegistry().RegistryMirrors {
|
||||
mirrorsArr = append(mirrorsArr, fmt.Sprintf("\"%s\"", mirror))
|
||||
mirrorsArr = append(mirrorsArr, fmt.Sprintf("%q", mirror))
|
||||
}
|
||||
m = strings.Join(mirrorsArr, ", ")
|
||||
}
|
||||
|
|
@ -284,7 +291,7 @@ func (s *ContainerdService) lookupCertsFile(path string) (ca string, cert string
|
|||
return
|
||||
}
|
||||
s.instanceScope.V(2).Info(fmt.Sprintf("Looking for TLS certificates and private keys in abs path %s", absPath))
|
||||
fs, err := ioutil.ReadDir(absPath)
|
||||
fs, err := os.ReadDir(absPath)
|
||||
if err != nil {
|
||||
return ca, cert, key, err
|
||||
}
|
||||
|
|
@ -318,16 +325,16 @@ func (s *ContainerdService) lookupCertsFile(path string) (ca string, cert string
|
|||
}
|
||||
|
||||
func (s *ContainerdService) installRunc() error {
|
||||
runc, err := s.getRuncService(s.SSHClient, file.RuncDefaultVersion, s.instanceScope.Arch())
|
||||
runc, err := s.getRuncService(s.sshClient, file.RuncDefaultVersion, s.instanceScope.Arch())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := s.SSHClient.SudoCmdf("install -m 755 %s /usr/local/sbin/runc", runc.RemotePath()); err != nil {
|
||||
if _, err := s.sshClient.SudoCmdf("install -m 755 %s /usr/local/sbin/runc", runc.RemotePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = s.SSHClient.SudoCmdf("rm -rf %s", runc.RemotePath())
|
||||
_, _ = s.sshClient.SudoCmdf("rm -rf %s", runc.RemotePath())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +362,7 @@ func (s *ContainerdService) installCrictl() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func hasFile(files []os.FileInfo, name string) bool {
|
||||
func hasFile(files []os.DirEntry, name string) bool {
|
||||
for _, f := range files {
|
||||
if f.Name() == name {
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 containermanager defines the operations on the remote instance's CRI.
|
||||
package containermanager
|
||||
|
|
@ -28,6 +28,8 @@ import (
|
|||
//go:embed templates
|
||||
var f embed.FS
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service interface {
|
||||
Type() string
|
||||
Version() string
|
||||
|
|
@ -36,6 +38,7 @@ type Service interface {
|
|||
Install() error
|
||||
}
|
||||
|
||||
// NewService returns a new service given the remote instance container manager client.
|
||||
func NewService(sshClient ssh.Interface, scope scope.KKInstanceScope, instanceScope *scope.InstanceScope) Service {
|
||||
switch instanceScope.ContainerManager().Type {
|
||||
case file.ContainerdID:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package service implements various services.
|
||||
package service
|
||||
|
||||
import (
|
||||
|
|
@ -22,6 +23,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/provisioning/commands"
|
||||
)
|
||||
|
||||
// Bootstrap is the interface for bootstrap provision.
|
||||
type Bootstrap interface {
|
||||
AddUsers() error
|
||||
SetHostname() error
|
||||
|
|
@ -34,11 +36,13 @@ type Bootstrap interface {
|
|||
DaemonReload() error
|
||||
}
|
||||
|
||||
// BinaryService is the interface for binary provision.
|
||||
type BinaryService interface {
|
||||
DownloadAll(timeout time.Duration) error
|
||||
ConfigureKubelet() error
|
||||
}
|
||||
|
||||
// ContainerManager is the interface for container manager provision.
|
||||
type ContainerManager interface {
|
||||
Type() string
|
||||
IsExist() bool
|
||||
|
|
@ -46,6 +50,7 @@ type ContainerManager interface {
|
|||
Install() error
|
||||
}
|
||||
|
||||
// Provisioning is the interface for bootstrap generate by CABPK provision.
|
||||
type Provisioning interface {
|
||||
RawBootstrapDataToProvisioningCommands(config []byte) ([]commands.Cmd, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,15 +17,18 @@
|
|||
package directory
|
||||
|
||||
const (
|
||||
TmpDir = "/tmp/kubekey"
|
||||
BinDir = "/usr/local/bin"
|
||||
KubeConfigDir = "/etc/kubernetes"
|
||||
KubeAddonsDir = "/etc/kubernetes/addons"
|
||||
KubeCertDir = "/etc/kubernetes/pki"
|
||||
KubeManifestDir = "/etc/kubernetes/manifests"
|
||||
KubeScriptDir = "/usr/local/bin/kube-scripts"
|
||||
// TmpDir represents the tmp directory of the remote instance
|
||||
TmpDir = "/tmp/kubekey"
|
||||
// BinDir represents the bin directory of the remote instance
|
||||
BinDir = "/usr/local/bin"
|
||||
// KubeConfigDir represents the normal kubernetes data directory of the remote instance
|
||||
KubeConfigDir = "/etc/kubernetes"
|
||||
// KubeCertDir represents the normal kubernetes cert directory of the remote instance
|
||||
KubeCertDir = "/etc/kubernetes/pki"
|
||||
// KubeManifestDir represents the normal kubernetes manifest directory of the remote instance
|
||||
KubeManifestDir = "/etc/kubernetes/manifests"
|
||||
// KubeScriptDir represents the kubernetes manage tools scripts directory of the remote instance
|
||||
KubeScriptDir = "/usr/local/bin/kube-scripts"
|
||||
// KubeletFlexvolumesPluginsDir represents the kubernetes kubelet plugin volume directory of the remote instance
|
||||
KubeletFlexvolumesPluginsDir = "/usr/libexec/kubernetes/kubelet-plugins/volume/exec"
|
||||
ETCDCertDir = "/etc/ssl/etcd/ssl"
|
||||
RegistryCertDir = "/etc/ssl/registry/ssl"
|
||||
HaproxyDir = "/etc/kubekey/haproxy"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,26 +24,29 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// Make wraps the Linux command "mkdir -p -m <mode> <path>".
|
||||
func (s *Service) Make() error {
|
||||
_, err := s.SSHClient.SudoCmdf("mkdir -p -m %o %s", filesystem.ToChmodPerm(s.Mode), s.Path)
|
||||
_, err := s.sshClient.SudoCmdf("mkdir -p -m %o %s", filesystem.ToChmodPerm(s.mode), s.path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to mkdir -p -m %o %s", filesystem.ToChmodPerm(s.Mode), s.Path)
|
||||
return errors.Wrapf(err, "failed to mkdir -p -m %o %s", filesystem.ToChmodPerm(s.mode), s.path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Chown wraps the linux command "chown <user> -R <path>".
|
||||
func (s *Service) Chown(user string) error {
|
||||
_, err := s.SSHClient.SudoCmd(fmt.Sprintf("chown %s -R %s", user, s.Path))
|
||||
_, err := s.sshClient.SudoCmd(fmt.Sprintf("chown %s -R %s", user, s.path))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to chown %s -R %s", user, s.Path)
|
||||
return errors.Wrapf(err, "failed to chown %s -R %s", user, s.path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove wraps the linux command "rm -rf <path>".
|
||||
func (s *Service) Remove() error {
|
||||
_, err := s.SSHClient.SudoCmd(fmt.Sprintf("rm -rf %s", s.Path))
|
||||
_, err := s.sshClient.SudoCmd(fmt.Sprintf("rm -rf %s", s.path))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to rm -rf %s", s.Path)
|
||||
return errors.Wrapf(err, "failed to rm -rf %s", s.path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 directory defines the operations on remote instance directory.
|
||||
package directory
|
||||
|
|
@ -23,17 +23,20 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service struct {
|
||||
SSHClient ssh.Interface
|
||||
Path string
|
||||
Mode os.FileMode
|
||||
sshClient ssh.Interface
|
||||
path string
|
||||
mode os.FileMode
|
||||
}
|
||||
|
||||
// NewService returns a new service given the remote instance directory client.
|
||||
func NewService(sshClient ssh.Interface, path string, mode os.FileMode) *Service {
|
||||
return &Service{
|
||||
SSHClient: sshClient,
|
||||
Path: path,
|
||||
Mode: checkFileMode(mode),
|
||||
sshClient: sshClient,
|
||||
path: path,
|
||||
mode: checkFileMode(mode),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,26 +19,24 @@ package directory
|
|||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
func Test_checkFileMode(t *testing.T) {
|
||||
tests := []struct {
|
||||
mode os.FileMode
|
||||
want filesystem.FileMode
|
||||
want os.FileMode
|
||||
}{
|
||||
{
|
||||
0,
|
||||
filesystem.FileMode{FileMode: os.ModeDir | os.FileMode(0644)},
|
||||
os.ModeDir | os.FileMode(0664),
|
||||
},
|
||||
{
|
||||
os.FileMode(0664),
|
||||
filesystem.FileMode{FileMode: os.ModeDir | os.FileMode(0664)},
|
||||
os.ModeDir | os.FileMode(0664),
|
||||
},
|
||||
{
|
||||
os.FileMode(0777),
|
||||
filesystem.FileMode{FileMode: os.ModeDir | os.FileMode(0777)},
|
||||
os.ModeDir | os.FileMode(0777),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@ package file
|
|||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
|
|
@ -32,6 +30,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// Binary is a binary implementation of Binary interface.
|
||||
type Binary struct {
|
||||
*File
|
||||
id string
|
||||
|
|
@ -42,37 +41,43 @@ type Binary struct {
|
|||
checksum checksum.Interface
|
||||
}
|
||||
|
||||
// ID returns the id of the binary.
|
||||
func (b *Binary) ID() string {
|
||||
return b.id
|
||||
}
|
||||
|
||||
// Arch returns the arch of the binary.
|
||||
func (b *Binary) Arch() string {
|
||||
return b.arch
|
||||
}
|
||||
|
||||
// Version returns the version of the binary.
|
||||
func (b *Binary) Version() string {
|
||||
return b.version
|
||||
}
|
||||
|
||||
func (b *Binary) Url() string {
|
||||
// URL returns the download url of the binary.
|
||||
func (b *Binary) URL() string {
|
||||
return b.url
|
||||
}
|
||||
|
||||
// SetZone sets the zone of the binary.
|
||||
func (b *Binary) SetZone(zone string) {
|
||||
if zone == "cn" {
|
||||
b.url = b.cnURL
|
||||
}
|
||||
}
|
||||
|
||||
// Get downloads the binary from remote.
|
||||
func (b *Binary) Get(timeout time.Duration) error {
|
||||
//todo: should not to skip TLS verify
|
||||
client := &getter.HttpGetter{
|
||||
ReadTimeout: timeout,
|
||||
Client: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
},
|
||||
//Client: &http.Client{
|
||||
// Transport: &http.Transport{
|
||||
// TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
// },
|
||||
//},
|
||||
}
|
||||
|
||||
url, err := urlhelper.Parse(b.url)
|
||||
|
|
@ -87,6 +92,7 @@ func (b *Binary) Get(timeout time.Duration) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SHA256 calculates the SHA256 of the binary.
|
||||
func (b *Binary) SHA256() (string, error) {
|
||||
f, err := os.Open(b.LocalPath())
|
||||
if err != nil {
|
||||
|
|
@ -94,13 +100,14 @@ func (b *Binary) SHA256() (string, error) {
|
|||
}
|
||||
defer f.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(f)
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%x", sha256.Sum256(data)), nil
|
||||
}
|
||||
|
||||
// CompareChecksum compares the checksum of the binary.
|
||||
func (b *Binary) CompareChecksum() error {
|
||||
if err := b.checksum.Get(); err != nil {
|
||||
return errors.Wrapf(err, "%s get checksum failed", b.Name())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 checksum implements methods for obtaining and verifying the checksum of binary files.
|
||||
package checksum
|
||||
|
|
@ -16,11 +16,13 @@
|
|||
|
||||
package checksum
|
||||
|
||||
// Interface is the interface for checksum.
|
||||
type Interface interface {
|
||||
Get() error
|
||||
Value() string
|
||||
}
|
||||
|
||||
// NewChecksum returns a new checksum implementation.
|
||||
func NewChecksum(id, version, arch string) Interface {
|
||||
return NewInternalChecksum(id, version, arch)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ const (
|
|||
runc = "runc"
|
||||
)
|
||||
|
||||
// InternalChecksum is the internal checksum implementation.
|
||||
type InternalChecksum struct {
|
||||
ID string
|
||||
Version string
|
||||
|
|
@ -46,6 +47,7 @@ type InternalChecksum struct {
|
|||
value string
|
||||
}
|
||||
|
||||
// NewInternalChecksum returns a new internal checksum implementation given the binary information.
|
||||
func NewInternalChecksum(id, version, arch string) *InternalChecksum {
|
||||
return &InternalChecksum{
|
||||
ID: id,
|
||||
|
|
@ -54,6 +56,7 @@ func NewInternalChecksum(id, version, arch string) *InternalChecksum {
|
|||
}
|
||||
}
|
||||
|
||||
// Get gets the internal checksum.
|
||||
func (i *InternalChecksum) Get() error {
|
||||
value, ok := FileSha256[i.ID][i.Arch][i.Version]
|
||||
if !ok {
|
||||
|
|
@ -63,11 +66,13 @@ func (i *InternalChecksum) Get() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Value returns the internal checksum value.
|
||||
func (i *InternalChecksum) Value() string {
|
||||
return i.value
|
||||
}
|
||||
|
||||
var (
|
||||
// FileSha256 is a hash table the storage the checksum of the binary files.
|
||||
FileSha256 = map[string]map[string]map[string]string{
|
||||
kubeadm: {
|
||||
amd64: {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package file
|
||||
|
||||
// Common dir
|
||||
const (
|
||||
TmpDir = "/tmp/kubekey"
|
||||
BinDir = "/usr/local/bin"
|
||||
OptCniBinDir = "/opt/cni/bin"
|
||||
SystemdDir = "/etc/systemd/system"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// Containerd info
|
||||
const (
|
||||
ContainerdName = "containerd-%s-linux-%s.tar.gz"
|
||||
ContainerdID = "containerd"
|
||||
|
|
@ -32,11 +33,12 @@ const (
|
|||
ContainerdDownloadURLTmplCN = "https://kubernetes-release.pek3b.qingstor.com/containerd/containerd/releases/download/v%s/containerd-%s-linux-%s.tar.gz"
|
||||
)
|
||||
|
||||
// NewContainerd returns a new Binary for containerd
|
||||
func NewContainerd(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(ContainerdID, version, arch)
|
||||
|
||||
fileName := fmt.Sprintf(ContainerdName, version, arch)
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// Crictl info
|
||||
const (
|
||||
CrictlName = "crictl-%s-linux-%s.tar.gz"
|
||||
CrictlID = "crictl"
|
||||
|
|
@ -32,11 +33,12 @@ const (
|
|||
CrictlDownloadURLTmplCN = "https://kubernetes-release.pek3b.qingstor.com/cri-tools/releases/download/%s/crictl-%s-linux-%s.tar.gz"
|
||||
)
|
||||
|
||||
// NewCrictl returns a new Binary for crictl
|
||||
func NewCrictl(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(CrictlID, version, arch)
|
||||
|
||||
fileName := fmt.Sprintf(CrictlName, version, arch)
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -14,22 +14,5 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package file defines the operations on the binaries.
|
||||
package file
|
||||
|
||||
import (
|
||||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/clients/ssh"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
SSHClient ssh.Interface
|
||||
Name string
|
||||
Type string
|
||||
LocalFullPath string
|
||||
RemoteFullPath string
|
||||
}
|
||||
|
||||
func NewService(sshClient ssh.Interface) *Service {
|
||||
return &Service{
|
||||
SSHClient: sshClient,
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util"
|
||||
)
|
||||
|
||||
// Docker info
|
||||
const (
|
||||
DockerName = "docker-%s.tgz"
|
||||
DockerID = "docker"
|
||||
|
|
@ -34,11 +35,12 @@ const (
|
|||
DockerDefaultVersion = "20.10.8"
|
||||
)
|
||||
|
||||
// NewDocker returns a new Binary for docker.
|
||||
func NewDocker(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(DockerID, version, arch)
|
||||
|
||||
fileName := fmt.Sprintf(DockerName, version)
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -25,24 +25,30 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/rootfs"
|
||||
)
|
||||
|
||||
type FileType string
|
||||
// Type represents the type of file.
|
||||
type Type string
|
||||
|
||||
var (
|
||||
FileBinary = FileType("fileBinary")
|
||||
FileText = FileType("fileText")
|
||||
FileTemplate = FileType("fileTemplate")
|
||||
// FileBinary represents a binary file.
|
||||
FileBinary = Type("fileBinary")
|
||||
// FileText represents a text file.
|
||||
FileText = Type("fileText")
|
||||
// FileTemplate represents a template file.
|
||||
FileTemplate = Type("fileTemplate")
|
||||
)
|
||||
|
||||
type FileParams struct {
|
||||
// Params represents the parameters of a file.
|
||||
type Params struct {
|
||||
SSHClient ssh.Interface
|
||||
Name string
|
||||
Type FileType
|
||||
Type Type
|
||||
LocalFullPath string
|
||||
RemoteFullPath string
|
||||
RootFs rootfs.Interface
|
||||
}
|
||||
|
||||
func NewFile(params FileParams) (*File, error) {
|
||||
// NewFile returns a new File object given a FileParams.
|
||||
func NewFile(params Params) (*File, error) {
|
||||
if params.SSHClient == nil {
|
||||
return nil, errors.New("ssh client is required when creating a File")
|
||||
}
|
||||
|
|
@ -62,39 +68,47 @@ func NewFile(params FileParams) (*File, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// File is an implementation of the File interface.
|
||||
type File struct {
|
||||
sshClient ssh.Interface
|
||||
name string
|
||||
fileType FileType
|
||||
fileType Type
|
||||
localFullPath string
|
||||
remoteFullPath string
|
||||
rootFs rootfs.Interface
|
||||
}
|
||||
|
||||
// Name returns the name of the file.
|
||||
func (s *File) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
func (s *File) Type() FileType {
|
||||
// Type returns the type of the file.
|
||||
func (s *File) Type() Type {
|
||||
return s.fileType
|
||||
}
|
||||
|
||||
// SetLocalPath sets the local path of the file.
|
||||
func (s *File) SetLocalPath(path string) {
|
||||
s.localFullPath = path
|
||||
}
|
||||
|
||||
// SetRemotePath sets the remote path of the file.
|
||||
func (s *File) SetRemotePath(path string) {
|
||||
s.remoteFullPath = path
|
||||
}
|
||||
|
||||
// LocalPath returns the local path of the file.
|
||||
func (s *File) LocalPath() string {
|
||||
return s.localFullPath
|
||||
}
|
||||
|
||||
// RemotePath returns the remote path of the file.
|
||||
func (s *File) RemotePath() string {
|
||||
return s.remoteFullPath
|
||||
}
|
||||
|
||||
// LocalExist returns true if the file exists in the local path.
|
||||
func (s *File) LocalExist() bool {
|
||||
_, err := os.Stat(s.LocalPath())
|
||||
if err != nil {
|
||||
|
|
@ -109,6 +123,7 @@ func (s *File) LocalExist() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// RemoteExist returns true if the file exists in the remote path.
|
||||
func (s *File) RemoteExist() bool {
|
||||
ok, err := s.sshClient.RemoteFileExist(s.RemotePath())
|
||||
if err != nil {
|
||||
|
|
@ -117,6 +132,7 @@ func (s *File) RemoteExist() bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
// Copy copies the file from the local path to the remote path.
|
||||
func (s *File) Copy(override bool) error {
|
||||
if !s.LocalExist() {
|
||||
return errors.Errorf("file %s is not exist in the local path %s", s.Name(), s.LocalPath())
|
||||
|
|
@ -130,6 +146,7 @@ func (s *File) Copy(override bool) error {
|
|||
return s.sshClient.Copy(s.LocalPath(), s.RemotePath())
|
||||
}
|
||||
|
||||
// Fetch copies the file from the remote path to the local path.
|
||||
func (s *File) Fetch(override bool) error {
|
||||
if !s.RemoteExist() {
|
||||
return errors.Errorf("remote file %s is not exist in the remote path %s", s.Name(), s.RemotePath())
|
||||
|
|
@ -143,6 +160,7 @@ func (s *File) Fetch(override bool) error {
|
|||
return s.sshClient.Fetch(s.LocalPath(), s.RemotePath())
|
||||
}
|
||||
|
||||
// Chmod changes the mode of the file.
|
||||
func (s *File) Chmod(option string) error {
|
||||
if !s.RemoteExist() {
|
||||
return errors.Errorf("remote file %s is not exist in the remote path %s", s.Name(), s.RemotePath())
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// Kubeadm info
|
||||
const (
|
||||
KubeadmName = "kubeadm"
|
||||
KubeadmID = "kubeadm"
|
||||
|
|
@ -32,11 +33,12 @@ const (
|
|||
KubeadmDownloadURLTmplCN = "https://kubernetes-release.pek3b.qingstor.com/release/%s/bin/linux/%s/kubeadm"
|
||||
)
|
||||
|
||||
// NewKubeadm returns a new Binary for kubeadm
|
||||
func NewKubeadm(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(KubeadmID, version, arch)
|
||||
|
||||
fileName := KubeadmName
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// Kubecni info
|
||||
const (
|
||||
KubecniName = "cni-plugins-linux-%s-%s.tgz"
|
||||
KubecniID = "kubecni"
|
||||
|
|
@ -33,11 +34,12 @@ const (
|
|||
KubecniDefaultVersion = "v0.9.1"
|
||||
)
|
||||
|
||||
// NewKubecni returns a new Binary for kubecni
|
||||
func NewKubecni(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(KubecniID, version, arch)
|
||||
|
||||
fileName := fmt.Sprintf(KubecniName, arch, version)
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// Kubectl info
|
||||
const (
|
||||
KubectlName = "kubectl"
|
||||
KubectlID = "kubectl"
|
||||
|
|
@ -32,11 +33,12 @@ const (
|
|||
KubectlDownloadURLTmplCN = "https://kubernetes-release.pek3b.qingstor.com/release/%s/bin/linux/%s/kubectl"
|
||||
)
|
||||
|
||||
// NewKubectl returns a new Binary for kubectl
|
||||
func NewKubectl(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(KubectlID, version, arch)
|
||||
|
||||
fileName := KubectlName
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// kubelet info
|
||||
const (
|
||||
KubeletName = "kubelet"
|
||||
KubeletID = "kubelet"
|
||||
|
|
@ -32,11 +33,12 @@ const (
|
|||
KubeletDownloadURLTmplCN = "https://kubernetes-release.pek3b.qingstor.com/release/%s/bin/linux/%s/kubelet"
|
||||
)
|
||||
|
||||
// NewKubelet returns a new Binary for kubelet
|
||||
func NewKubelet(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(KubeletID, version, arch)
|
||||
|
||||
fileName := KubeletName
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file/checksum"
|
||||
)
|
||||
|
||||
// runc info
|
||||
const (
|
||||
RuncName = "runc.%s"
|
||||
RuncID = "runc"
|
||||
|
|
@ -33,11 +34,12 @@ const (
|
|||
RuncDefaultVersion = "v1.1.1"
|
||||
)
|
||||
|
||||
// NewRunc returns a new Binary for runc
|
||||
func NewRunc(sshClient ssh.Interface, rootFs rootfs.Interface, version, arch string) (*Binary, error) {
|
||||
internal := checksum.NewChecksum(RuncID, version, arch)
|
||||
|
||||
fileName := fmt.Sprintf(RuncName, arch)
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Type: FileBinary,
|
||||
|
|
|
|||
|
|
@ -26,8 +26,10 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// Data is the data that will be passed to the template.
|
||||
type Data map[string]interface{}
|
||||
|
||||
// Template is an implementation of the Template interface.
|
||||
type Template struct {
|
||||
*File
|
||||
template *template.Template
|
||||
|
|
@ -35,8 +37,9 @@ type Template struct {
|
|||
dst string
|
||||
}
|
||||
|
||||
// NewTemplate returns a new Template.
|
||||
func NewTemplate(sshClient ssh.Interface, rootFs rootfs.Interface, template *template.Template, data Data, dst string) (*Template, error) {
|
||||
file, err := NewFile(FileParams{
|
||||
file, err := NewFile(Params{
|
||||
SSHClient: sshClient,
|
||||
RootFs: rootFs,
|
||||
Name: template.Name(),
|
||||
|
|
@ -55,6 +58,7 @@ func NewTemplate(sshClient ssh.Interface, rootFs rootfs.Interface, template *tem
|
|||
}, nil
|
||||
}
|
||||
|
||||
// RenderToLocal renders the template to the local filesystem.
|
||||
func (t *Template) RenderToLocal() error {
|
||||
dir := filepath.Dir(t.localFullPath)
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package operation define the remote instance operations interface.
|
||||
package operation
|
||||
|
||||
import (
|
||||
|
|
@ -22,9 +23,10 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/operation/file"
|
||||
)
|
||||
|
||||
// File interface defines the operations for normal file which needed to be copied to remote.
|
||||
type File interface {
|
||||
Name() string
|
||||
Type() file.FileType
|
||||
Type() file.Type
|
||||
LocalPath() string
|
||||
RemotePath() string
|
||||
LocalExist() bool
|
||||
|
|
@ -34,32 +36,38 @@ type File interface {
|
|||
Chmod(option string) error
|
||||
}
|
||||
|
||||
// Binary interface defines the operations for Kubernetes needed binaries which usually needed to be copied to remote.
|
||||
type Binary interface {
|
||||
File
|
||||
ID() string
|
||||
Arch() string
|
||||
Version() string
|
||||
Url() string
|
||||
URL() string
|
||||
SetZone(zone string)
|
||||
Get(timeout time.Duration) error
|
||||
CompareChecksum() error
|
||||
}
|
||||
|
||||
// Template interface defines the operations for Kubernetes needed template files (systemd files, config files .e.g)
|
||||
// which usually needed to be copied to remote.
|
||||
type Template interface {
|
||||
File
|
||||
RenderToLocal() error
|
||||
}
|
||||
|
||||
// User interface defines the operations for remote instance Linux user.
|
||||
type User interface {
|
||||
Add() error
|
||||
}
|
||||
|
||||
// Directory interface defines the operations for remote instance Linux directory.
|
||||
type Directory interface {
|
||||
Make() error
|
||||
Chown(user string) error
|
||||
Remove() error
|
||||
}
|
||||
|
||||
// Repository interface defines the operations for remote instance Linux repository.
|
||||
type Repository interface {
|
||||
Update() error
|
||||
Install(pkg ...string) error
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 repository defines the operations on the remote instance linux software packages repository.
|
||||
package repository
|
||||
|
|
@ -22,16 +22,19 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/clients/ssh"
|
||||
)
|
||||
|
||||
// Debian is a repository manager implementation for Debian.
|
||||
type Debian struct {
|
||||
SSHClient ssh.Interface
|
||||
}
|
||||
|
||||
// NewDeb returns a new Debian repository manager
|
||||
func NewDeb(sshClient ssh.Interface) *Debian {
|
||||
return &Debian{
|
||||
SSHClient: sshClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates the repository cache
|
||||
func (d *Debian) Update() error {
|
||||
if _, err := d.SSHClient.Cmd("sudo apt-get update"); err != nil {
|
||||
return err
|
||||
|
|
@ -39,6 +42,7 @@ func (d *Debian) Update() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Install installs common packages
|
||||
func (d *Debian) Install(pkg ...string) error {
|
||||
if len(pkg) == 0 {
|
||||
pkg = []string{"socat", "conntrack", "ipset", "ebtables", "chrony", "ipvsadm"}
|
||||
|
|
|
|||
|
|
@ -22,16 +22,19 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/clients/ssh"
|
||||
)
|
||||
|
||||
// RedhatPackageManager is a repository manager implementation for Redhat, Centos.
|
||||
type RedhatPackageManager struct {
|
||||
SSHClient ssh.Interface
|
||||
}
|
||||
|
||||
// NewRPM returns a new RedhatPackageManager.
|
||||
func NewRPM(sshClient ssh.Interface) *RedhatPackageManager {
|
||||
return &RedhatPackageManager{
|
||||
SSHClient: sshClient,
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates the repository cache.
|
||||
func (r *RedhatPackageManager) Update() error {
|
||||
if _, err := r.SSHClient.SudoCmd("yum clean all && yum makecache"); err != nil {
|
||||
return err
|
||||
|
|
@ -39,11 +42,12 @@ func (r *RedhatPackageManager) Update() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Install installs common packages.
|
||||
func (r *RedhatPackageManager) Install(pkg ...string) error {
|
||||
if len(pkg) == 0 {
|
||||
pkg = []string{"openssl", "socat", "conntrack", "ipset", "ebtables", "chrony", "ipvsadm"}
|
||||
}
|
||||
if _, err := r.SSHClient.SudoCmdf("apt install -y %s", strings.Join(pkg, " ")); err != nil {
|
||||
if _, err := r.SSHClient.SudoCmdf("yum install -y %s", strings.Join(pkg, " ")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -22,13 +22,15 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/clients/ssh"
|
||||
)
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service interface {
|
||||
Update() error
|
||||
Install(pkg ...string) error
|
||||
}
|
||||
|
||||
// NewService returns a new service given the remote instance package manager client.
|
||||
func NewService(sshClient ssh.Interface, os string) Service {
|
||||
|
||||
switch strings.ToLower(os) {
|
||||
case "ubuntu", "debian":
|
||||
return NewDeb(sshClient)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 user defines the user operations on the remote instance.
|
||||
package user
|
||||
|
|
@ -20,12 +20,15 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/clients/ssh"
|
||||
)
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service struct {
|
||||
SSHClient ssh.Interface
|
||||
Name string
|
||||
Desc string
|
||||
}
|
||||
|
||||
// NewService returns a new service given the remote instance Linux user.
|
||||
func NewService(sshClient ssh.Interface, name, desc string) *Service {
|
||||
return &Service{
|
||||
SSHClient: sshClient,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Add adds a new Linux user to the remote instance.
|
||||
func (s *Service) Add() error {
|
||||
_, err := s.SSHClient.SudoCmd(fmt.Sprintf("useradd -M -c '%s' -s /sbin/nologin -r %s || :", s.Desc, s.Name))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ type actionFactory struct {
|
|||
sshClient ssh.Interface
|
||||
}
|
||||
|
||||
// NewActionFactory returns a new action factory.
|
||||
func NewActionFactory(sshClient ssh.Interface) *actionFactory {
|
||||
return &actionFactory{
|
||||
sshClient: sshClient,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 cloudinit defines cloud init adapter for existing nodes.
|
||||
package cloudinit
|
||||
|
|
@ -42,16 +42,18 @@ func (a *runCmd) Unmarshal(userData []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Commands returns the commands.
|
||||
func (a *runCmd) Commands() ([]commands.Cmd, error) {
|
||||
cmds := make([]commands.Cmd, 0)
|
||||
for _, c := range a.Cmds {
|
||||
// kubeadm in docker requires to ignore some errors, and this requires to modify the cmd generate by CABPK by default...
|
||||
// requires to ignore some errors, and this requires to modify the cmd generate by CABPK by default...
|
||||
c = hackKubeadmIgnoreErrors(c)
|
||||
cmds = append(cmds, c)
|
||||
}
|
||||
return cmds, nil
|
||||
}
|
||||
|
||||
// Run runs the commands.
|
||||
func (a *runCmd) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,16 +24,20 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/provisioning/commands"
|
||||
)
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service struct {
|
||||
SSHClient ssh.Interface
|
||||
}
|
||||
|
||||
// NewService returns a new service.
|
||||
func NewService(sshClient ssh.Interface) *Service {
|
||||
return &Service{
|
||||
SSHClient: sshClient,
|
||||
}
|
||||
}
|
||||
|
||||
// RawBootstrapDataToProvisioningCommands converts raw bootstrap data to provisioning commands.
|
||||
func (s *Service) RawBootstrapDataToProvisioningCommands(config []byte) ([]commands.Cmd, error) {
|
||||
// validate cloudConfigScript is a valid yaml, as required by the cloud config specification
|
||||
if err := yaml.Unmarshal(config, &map[string]interface{}{}); err != nil {
|
||||
|
|
|
|||
|
|
@ -56,10 +56,12 @@ func (u *unknown) Unmarshal(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Commands returns the commands to run for the unknown action.
|
||||
func (u *unknown) Commands() ([]commands.Cmd, error) {
|
||||
return []commands.Cmd{}, nil
|
||||
}
|
||||
|
||||
// Run runs the commands for the unknown action.
|
||||
func (u *unknown) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ func (a *writeFilesAction) getDirectoryService(path string, mode os.FileMode) op
|
|||
return directory.NewService(a.sshClient, path, mode)
|
||||
}
|
||||
|
||||
// Unmarshal unmarshals the given content into the given encoding.
|
||||
func (a *writeFilesAction) Unmarshal(userData []byte) error {
|
||||
if err := yaml.Unmarshal(userData, a); err != nil {
|
||||
return errors.Wrapf(err, "error parsing write_files action: %s", userData)
|
||||
|
|
@ -129,6 +130,7 @@ func (a *writeFilesAction) Commands() ([]commands.Cmd, error) {
|
|||
return cmds, nil
|
||||
}
|
||||
|
||||
// Run runs the action.
|
||||
func (a *writeFilesAction) Run() error {
|
||||
for _, f := range a.Files {
|
||||
// Fix attributes and apply defaults
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package provisioning deals with various machine initialization methods viz. cloud-init, Ignition,
|
||||
// Package commands deals with various machine initialization methods viz. cloud-init, Ignition,
|
||||
// etc.
|
||||
package commands
|
||||
|
||||
|
|
@ -61,12 +61,12 @@ func (c *Cmd) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// String returns the command as a string.
|
||||
func (c *Cmd) String() string {
|
||||
|
||||
cmd := strings.Join(append([]string{c.Cmd}, c.Args...), " ")
|
||||
if strings.HasPrefix(cmd, "/bin/sh -c") {
|
||||
cmd = strings.TrimPrefix(cmd, "/bin/sh -c")
|
||||
} else if strings.HasPrefix(cmd, "/bin/bash -c") {
|
||||
} else {
|
||||
cmd = strings.TrimPrefix(cmd, "/bin/bash -c")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package provisioning defines the provisioning operations on the remote instance generated by cloudinit or ignition.
|
||||
package provisioning
|
||||
|
||||
import (
|
||||
|
|
@ -24,10 +25,13 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/service/provisioning/commands"
|
||||
)
|
||||
|
||||
// Service holds a collection of interfaces.
|
||||
// The interfaces are broken down like this to group functions together.
|
||||
type Service interface {
|
||||
RawBootstrapDataToProvisioningCommands(config []byte) ([]commands.Cmd, error)
|
||||
}
|
||||
|
||||
// NewService returns a new service given the cloud config format client.
|
||||
func NewService(sshClient ssh.Interface, format bootstrapv1.Format) Service {
|
||||
switch format {
|
||||
case bootstrapv1.CloudConfig:
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@
|
|||
package filesystem
|
||||
|
||||
const (
|
||||
// DefaultLocalTmpDir represents the CAPKK default local tmp directory
|
||||
DefaultLocalTmpDir = "/var/lib/kubekey"
|
||||
)
|
||||
|
||||
const (
|
||||
// FileMode0755 represents the file mode 0755
|
||||
FileMode0755 = 0755
|
||||
// FileMode0644 represents the file mode 0644
|
||||
FileMode0644 = 0644
|
||||
// FileMode0664 represents the file mode 0664
|
||||
FileMode0664 = 0664
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2022 The KubeSphere 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 filesystem implements the operation of the local file system.
|
||||
package filesystem
|
||||
|
|
@ -22,9 +22,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
s_ISUID = syscall.S_ISUID
|
||||
s_ISGID = syscall.S_ISGID
|
||||
s_ISVTX = syscall.S_ISVTX
|
||||
sIsuid = syscall.S_ISUID
|
||||
sIsgid = syscall.S_ISGID
|
||||
sIsvtx = syscall.S_ISVTX
|
||||
)
|
||||
|
||||
// ToChmodPerm converts Go permission bits to POSIX permission bits.
|
||||
|
|
@ -33,17 +33,17 @@ const (
|
|||
// setuid, setgid and sticky in m, because we've historically supported those
|
||||
// bits, and we mask off any non-permission bits.
|
||||
func ToChmodPerm(m os.FileMode) (perm uint32) {
|
||||
const mask = os.ModePerm | s_ISUID | s_ISGID | s_ISVTX
|
||||
const mask = os.ModePerm | sIsuid | sIsgid | sIsvtx
|
||||
perm = uint32(m & mask)
|
||||
|
||||
if m&os.ModeSetuid != 0 {
|
||||
perm |= s_ISUID
|
||||
perm |= sIsuid
|
||||
}
|
||||
if m&os.ModeSetgid != 0 {
|
||||
perm |= s_ISGID
|
||||
perm |= sIsgid
|
||||
}
|
||||
if m&os.ModeSticky != 0 {
|
||||
perm |= s_ISVTX
|
||||
perm |= sIsvtx
|
||||
}
|
||||
|
||||
return perm
|
||||
|
|
|
|||
|
|
@ -24,21 +24,26 @@ import (
|
|||
"github.com/kubesphere/kubekey/exp/cluster-api-provider-kubekey/pkg/util/hash"
|
||||
)
|
||||
|
||||
// FileSystem is a filesystem implementation
|
||||
type FileSystem struct {
|
||||
}
|
||||
|
||||
// NewFileSystem returns a new CAPKK local filesystem implementation
|
||||
func NewFileSystem() Interface {
|
||||
return FileSystem{}
|
||||
}
|
||||
|
||||
// Stat returns the FileInfo for the given path
|
||||
func (f FileSystem) Stat(name string) (os.FileInfo, error) {
|
||||
return os.Stat(name)
|
||||
}
|
||||
|
||||
// MkdirAll the same as os.MkdirAll().
|
||||
func (f FileSystem) MkdirAll(path string) error {
|
||||
return os.MkdirAll(path, os.ModePerm)
|
||||
}
|
||||
|
||||
// MD5Sum returns the file MD5 sum for the given local path
|
||||
func (f FileSystem) MD5Sum(localPath string) string {
|
||||
md5, err := hash.FileMD5(localPath)
|
||||
if err != nil {
|
||||
|
|
@ -47,6 +52,7 @@ func (f FileSystem) MD5Sum(localPath string) string {
|
|||
return md5
|
||||
}
|
||||
|
||||
// MkLocalTmpDir creates a temporary directory and returns the path
|
||||
func (f FileSystem) MkLocalTmpDir() (string, error) {
|
||||
tempDir, err := ioutil.TempDir(DefaultLocalTmpDir, ".Tmp-")
|
||||
if err != nil {
|
||||
|
|
@ -55,6 +61,7 @@ func (f FileSystem) MkLocalTmpDir() (string, error) {
|
|||
return tempDir, os.MkdirAll(tempDir, os.ModePerm)
|
||||
}
|
||||
|
||||
// RemoveAll the same as os.RemoveAll().
|
||||
func (f FileSystem) RemoveAll(path ...string) error {
|
||||
for _, fi := range path {
|
||||
err := os.RemoveAll(fi)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,16 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
// Interface is an interface for filesystem operations
|
||||
type Interface interface {
|
||||
// Stat returns the FileInfo structure describing the named file.
|
||||
Stat(name string) (os.FileInfo, error)
|
||||
// MkdirAll the same as os.MkdirAll().
|
||||
MkdirAll(path string) error
|
||||
// MD5Sum returns the file MD5 sum for the given local path.
|
||||
MD5Sum(localPath string) string
|
||||
// MkLocalTmpDir creates a temporary directory and returns the path.
|
||||
MkLocalTmpDir() (string, error)
|
||||
// RemoveAll the same as os.RemoveAll().
|
||||
RemoveAll(path ...string) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,24 +14,25 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package hash implements hash utilities
|
||||
package hash
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/md5" // #nosec
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
//FileMD5 count file md5
|
||||
// FileMD5 count file md5
|
||||
func FileMD5(path string) (string, error) {
|
||||
file, err := os.Open(filepath.Clean(path))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
m := md5.New()
|
||||
m := md5.New() // #nosec
|
||||
if _, err := io.Copy(m, file); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue