feat: add go lint

Signed-off-by: 24sama <jacksama@foxmail.com>
This commit is contained in:
24sama 2022-08-19 16:06:10 +08:00
parent 66c521fbd0
commit 08cb08b870
105 changed files with 1580 additions and 732 deletions

29
.github/workflows/golangci-lint.yml vendored Normal file
View File

@ -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}}

View File

@ -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

View File

@ -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: //')

View File

@ -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"

View File

@ -16,6 +16,7 @@
package v1beta1
// Default values.
const (
DockerType = "docker"
DefaultDockerVersion = "20.10.8"

View File

@ -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

View File

@ -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 (

View File

@ -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))
}

View File

@ -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
}

View File

@ -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

View File

@ -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).

View File

@ -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")

View File

@ -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"

View File

@ -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())
})

View File

@ -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

View File

@ -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: []

View File

@ -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: []

View File

@ -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: []

View File

@ -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: []

View File

@ -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: []

View File

@ -1,4 +1,3 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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 {

View File

@ -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(

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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"))

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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
}

View File

@ -14,6 +14,7 @@
limitations under the License.
*/
// Package pkg defines the interface for a cluster scope.
package pkg
import (

View File

@ -16,6 +16,7 @@
package rootfs
// common dir.
const (
DefaultLocalTmpDir = "/var/lib/kubekey"
DefaultLocalRootFsDir = "/var/lib/kubekey/rootfs"

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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{}

View File

@ -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

View File

@ -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
}

View File

@ -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.

View File

@ -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

View File

@ -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()),

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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,

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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)
}

View File

@ -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"
)

View File

@ -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
}

View File

@ -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

View File

@ -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),
}
}

View File

@ -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 {

View File

@ -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())

View File

@ -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

View File

@ -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)
}

View File

@ -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: {

View File

@ -16,8 +16,8 @@
package file
// Common dir
const (
TmpDir = "/tmp/kubekey"
BinDir = "/usr/local/bin"
OptCniBinDir = "/opt/cni/bin"
SystemdDir = "/etc/systemd/system"

View File

@ -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,

View File

@ -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,

View File

@ -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,
}
}

View File

@ -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,

View File

@ -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())

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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"}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -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,

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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")
}

View File

@ -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:

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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