diff --git a/.rules/.golangci.yml b/.rules/.golangci.yml
index 60efa0037..75c54ba56 100644
--- a/.rules/.golangci.yml
+++ b/.rules/.golangci.yml
@@ -80,6 +80,40 @@ linters-settings:
extra-rules: true
goimports:
local-prefixes: github.com/sighupio
+ gomoddirectives:
+ # we need to use replace to be able to use Internal Kubernetes libraries
+ # needed for the create PKI feature.
+ replace-allow-list:
+ - k8s.io/api
+ - k8s.io/apiextensions-apiserver
+ - k8s.io/apimachinery
+ - k8s.io/apiserver
+ - k8s.io/cli-runtime
+ - k8s.io/client-go
+ - k8s.io/cloud-provider
+ - k8s.io/cluster-bootstrap
+ - k8s.io/code-generator
+ - k8s.io/component-base
+ - k8s.io/component-helpers
+ - k8s.io/controller-manager
+ - k8s.io/cri-api
+ - k8s.io/csi-translation-lib
+ - k8s.io/dynamic-resource-allocation
+ - k8s.io/endpointslice
+ - k8s.io/kms
+ - k8s.io/kube-aggregator
+ - k8s.io/kube-controller-manager
+ - k8s.io/kube-proxy
+ - k8s.io/kube-scheduler
+ - k8s.io/kubectl
+ - k8s.io/kubelet
+ - k8s.io/legacy-cloud-providers
+ - k8s.io/metrics
+ - k8s.io/mount-utils
+ - k8s.io/pod-security-admission
+ - k8s.io/sample-apiserver
+ - k8s.io/sample-cli-plugin
+ - k8s.io/sample-controller
gosec:
excludes:
- G204
diff --git a/Makefile b/Makefile
index 1a4817fba..d85598bc3 100644
--- a/Makefile
+++ b/Makefile
@@ -148,7 +148,13 @@ test-integration:
@GOFLAGS=-mod=mod go test -v -tags=integration -timeout 120s ./...
test-e2e:
- @GOFLAGS=-mod=mod ginkgo run -vv --trace -tags=e2e -timeout 600s -p test/e2e
+ @export KFD_AUTH_DEX_CONNECTORS_GITHUB_CLIENT_ID=dummy && \
+ export KFD_AUTH_DEX_CONNECTORS_GITHUB_CLIENT_SECRET=dummy && \
+ export KFD_BASIC_AUTH_PASSWORD=dummy && \
+ export KFD_AUTH_POMERIUM_COOKIE_SECRET=dummy && \
+ export KFD_AUTH_POMERIUM_IDP_CLIENT_SECRET=dummy && \
+ export KFD_AUTH_POMERIUM_SHARED_SECRET=dummy && \
+ GOFLAGS=-mod=mod ginkgo run -vv --trace -tags=e2e -timeout 600s -p test/e2e
test-expensive:
$(call yes-or-no, "WARNING: This test will create a cluster on AWS. Are you sure you want to continue?")
diff --git a/README.md b/README.md
index 5fa6c90c7..be8af4538 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,8 @@
The Swiss Army Knife
for the Kubernetes Fury Distribution
-
-
-[![Build Status](https://ci.sighup.io/api/badges/sighupio/furyctl/status.svg)](https://ci.sighup.io/sighupio/furyctl)
-![Release](https://img.shields.io/badge/furyctl-v0.29.3-blue)
+[![Build Status](https://ci.sighup.io/api/badges/sighupio/furyctl/status.svg?ref=refs/heads/main)](https://ci.sighup.io/sighupio/furyctl)
+![Release](https://img.shields.io/badge/furyctl-v0.29.4-blue)
![Slack](https://img.shields.io/badge/slack-@kubernetes/fury-yellow.svg?logo=slack)
![License](https://img.shields.io/github/license/sighupio/furyctl)
[![Go Report Card](https://goreportcard.com/badge/github.com/sighupio/furyctl)](https://goreportcard.com/report/github.com/sighupio/furyctl)
@@ -21,7 +19,7 @@
> The next generation of `furyctl`, called "furyctl next", has been officially released. It is now in a stable state and available starting from version v0.25.0. The previous version, furyctl 0.11, is considered legacy and will only receive bug fixes. It will be maintained under the v0.11 branch.
-## What is Furyctl?
+## What is furyctl?
`furyctl` is the command line companion for the Kubernetes Fury Distribution to manage the **full lifecycle** of your Kubernetes Fury clusters.
@@ -56,15 +54,6 @@ sudo mv /tmp/furyctl /usr/local/bin/furyctl
Alternatively, you can install `furyctl` using the asdf plugin.
-
-
### Installing with [asdf](https://github.com/asdf-vm/asdf)
Add furyctl asdf plugin:
@@ -80,7 +69,7 @@ $ furyctl version
...
goVersion: go1.22
osArch: amd64
-version: 0.29.3
+version: 0.29.4
```
### Installing from source
@@ -101,8 +90,6 @@ Once you've ensured the above dependencies are installed, you can proceed with t
1. Clone the repository:
-
-
```console
git clone git@github.com:sighupio/furyctl.git
# cd into the cloned repository
@@ -112,31 +99,31 @@ cd furyctl
2. Build the binaries by running the following command:
```console
-make build
+go build .
```
-3. You will find the binaries for Linux and Darwin (macOS) for your current architecture inside the `dist` folder:
+3. You will find the binaries for your current architecture inside the current folder:
```console
-$ tree dist/furyctl_*/
-dist/furyctl_darwin_amd64_v1
-└── furyctl
-dist/furyctl_linux_amd64_v1
-└── furyctl
+$ ls furyctl
+furyctl
```
4. Check that the binary is working as expected:
-> **Note** replace `darwin` with your OS and `amd64` with your architecture in the following commands.
-
```console
-./dist/furyctl_darwin_amd64_v1/furyctl version
+$ ./furyctl version
+buildTime: unknown
+gitCommit: unknown
+goVersion: unknown
+osArch: unknown
+version: unknown
```
5. (optional) move the binary to your `bin` folder, in macOS:
```console
-sudo mv ./dist/furyctl_darwin_amd64_v1/furyctl /usr/local/bin/furyctl
+sudo mv ./furyctl /usr/local/bin/furyctl
```
## Usage
@@ -150,13 +137,20 @@ See all the available commands and their usage by running `furyctl help`.
-> Check [KFD Compatibility matrix](https://github.com/sighupio/fury-distribution/blob/main/docs/COMPATIBILITY_MATRIX.md) for the Furyctl / KFD versions to use.
+> 💡 **TIP**
+>
+> You can follow the Kubernetes Fury Distribution quick start guides in KFD's official documentation site:
+>
+
+
+
+> Check [KFD Compatibility matrix](https://github.com/sighupio/fury-distribution/blob/main/docs/COMPATIBILITY_MATRIX.md) for the furyctl / KFD versions to use.
### Basic Usage
Basic usage of `furyctl` for a new project consists on the following steps:
-1. Creating a configuration file defining the prequired infrastructure, Kubernetes cluster details, and KFD modules configuration.
+1. Creating a configuration file defining the required infrastructure, Kubernetes cluster details, and KFD modules configuration.
2. Creating a cluster as defined in the configuration file.
3. Destroying the cluster and its related resources.
@@ -164,11 +158,11 @@ Basic usage of `furyctl` for a new project consists on the following steps:
`furyctl` provides a command that outputs a sample configuration file (by default called `furyctl.yaml`) with all the possible fields explained in comments.
-Furyctl configuration files have a kind that specifies what type of cluster will be created, for example the `EKSCluster` kind has all the parameters needed to create a KFD cluster using the EKS managed clusters from AWS.
+furyctl configuration files have a kind that specifies what type of cluster will be created, for example the `EKSCluster` kind has all the parameters needed to create a KFD cluster using the EKS managed clusters from AWS.
You can also use the `KFDDistribution` kind to install the KFD distribution on top of an existing Kubernetes cluster or `OnPremises` kind to install a KFD cluster on VMs.
-Additionaly, the schema of the file is versioned with the `apiVersion` field, so when new features are introduced you can switch to a newer version of the configuration file structure.
+Additionally, the schema of the file is versioned with the `apiVersion` field, so when new features are introduced you can switch to a newer version of the configuration file structure.
To scaffold a configuration file to use as a starter, you use the following command:
@@ -184,7 +178,7 @@ furyctl create config --version v1.29.1 --kind "EKSCluster"
Open the generated configuration file with your editor of choice and edit it according to your needs. You can follow the instructions included as comments in the file.
-Once you have filled your configuration file, you can check that it's content is valid by running the following comand:
+Once you have filled your configuration file, you can check that it's content is valid by running the following command:
```console
furyctl validate config --config /path/to/your/furyctl.yaml
@@ -201,9 +195,9 @@ Requirements (EKSCluster):
- AWS CLI
- OpenVPN (when filling the `vpn` field in the configuration file)
-In the previous step, you have created and validated a configuration file that defines the Kubernetes cluster and its sorroundings, you can now proceed to actually creating the resources.
+In the previous step, you have created and validated a configuration file that defines the Kubernetes cluster and its surroundings, you can now proceed to actually creating the resources.
-Furyctl divides the cluster creation in four phases: `infrastructure`, `kubernetes`, `distribution` and `plugins`.
+furyctl divides the cluster creation in four phases: `infrastructure`, `kubernetes`, `distribution` and `plugins`.
1. The first phase, `infrastructure`, creates all the prerequisites needed to be able to create a cluster. For example, the VPC and its networks.
2. The second phase, `kubernetes`, creates the actual Kubernetes clusters. For example, the EKS cluster and its node pools.
@@ -214,7 +208,7 @@ Furyctl divides the cluster creation in four phases: `infrastructure`, `kubernet
>
> You will find these four phases when editing the furyctl.yaml file.
-Just like you can validate that your configuration file is well formed, `furyctl` let you check that you have all the needed dependencies (environment variables, binaries, etc.) before starting a cluster creation process.
+Just like you can validate that your configuration file is well-formed, `furyctl` let you check that you have all the needed dependencies (environment variables, binaries, etc.) before starting a cluster creation process.
To validate that your system has all the dependencies needed to create the cluster defined in your configuration file, run the following command:
@@ -241,7 +235,7 @@ furyctl create cluster --config /path/to/your/furyctl.yaml
> 💡 **TIP**
>
> You can use the alias `furyctl apply` instead of `furyctl create cluster`.
-
+
> 📖 **NOTE**
>
> The creation process will take a while.
@@ -252,7 +246,7 @@ furyctl create cluster --config /path/to/your/furyctl.yaml
Upgrading a cluster is a process that can be divided into two steps: upgrading the fury version and running the migrations (if present).
-The first step consist in bringing the cluster up to date with the latest version of the Kubernetes Fury Distribution. This is done by running the following command:
+The first step consists in bringing the cluster up to date with the latest version of the Kubernetes Fury Distribution. This is done by running the following command:
```console
furyctl apply --upgrade --config /path/to/your/furyctl.yaml
@@ -342,6 +336,24 @@ The following steps will guide you through the process of creating a Kubernetes
4. Run `furyctl create cluster` to create the cluster.
5. (Optional) Watch the logs of the cluster creation process with `tail -f ~/.furyctl/furyctl.-.log`.
+#### Create the PKI for on-premises clusters
+
+On-premises clusters need a set of certificates authorities and certificate files to work as a prerequisite. Both for the Kubernetes control plane and for the etcd database.
+
+furyctl provides a command that allows the creation of this PKI:
+
+```bash
+furyctl create pki
+```
+
+The command supports some additional options, like `--etcd` to create only the PKI for etcd, or creating the files in a different path.
+
+See all the additional options with the `--help` flag:
+
+```bash
+furyctl create pki --help
+```
+
#### Create a cluster in an already existing infrastructure
Same as the previous section, but you can skip the infrastructure creation phase
@@ -378,9 +390,9 @@ to use the flag `--kubeconfig` in the following command.
furyctl create cluster --phase distribution
```
-#### Legacy download
+#### Legacy vendor download
-The new furyctl still embed some of the legacy features, for example the command `furyctl legacy vendor` to download KFD dependencies from a deprecated `Furyfile.yml`.
+The new furyctl still embeds some legacy features, for example the command `furyctl legacy vendor` to download KFD dependencies from a deprecated `Furyfile.yml`.
This can be still used to manually manage all the components of the distribution.
@@ -390,11 +402,14 @@ This can be still used to manually manage all the components of the distribution
#### Plugins
-Furyctl supports Helm and Kustomize plugins.
+furyctl supports Helm and Kustomize plugins.
##### Helm plugins
-To install an Helm plugin (chart), first you have to add the repository to the `spec.plugins.helm.repositories` section of your `furyctl.yaml` file and then you can add the release to the `spec.plugins.helm.releases` section, specifying the chart name, the namespace, the chart version and the values to override. To override the values you can use the `spec.plugins.helm.releases[].set` or the `spec.plugins.helm.releases[].values` section.
+To install a Helm plugin (chart), follow these steps:
+
+1. Add the repository to the `spec.plugins.helm.repositories` section of your `furyctl.yaml` file.
+2. Add the release to the `spec.plugins.helm.releases` section, specifying the chart name, the namespace, the chart version and the values to override. To override the values you can use the `spec.plugins.helm.releases[].set` or the `spec.plugins.helm.releases[].values` section.
For example to install the Prometheus Helm chart you have to add the following to your `furyctl.yaml`:
@@ -439,11 +454,11 @@ spec:
#### Using a custom distribution location
-Furyctl comes with the flag `--distro-location`, allowing you to use a local copy of KFD instead of downloading it from the internet. This allows you to test changes to the KFD without having to push them to the repository, and might come in handy when you need to test new features or bugfixes.
+furyctl comes with the flag `--distro-location`, allowing you to use a local copy of KFD instead of downloading it from the internet. This allows you to test changes to the KFD without having to push them to the repository, and might come in handy when you need to test new features or bug fixes.
#### Using a custom upgrade path location
-On the same note, the tool comes with the `--upgrade-path-location` flag, too, allowing you to test changes to the upgrade path without having to push them to the repository, and to support cases that are not covered by the official release, such as upgrading from a beta or rc release to a stable one.
+On the same note, the tool comes with the `--upgrade-path-location` flag, too, allowing you to test changes to the upgrade path without having to push them to the repository, and to support cases that are not covered by the official release, such as upgrading from a beta or release candidate release to a stable one.
#### Restarting the cluster creation or update process from a specific (sub-)phase
@@ -454,10 +469,10 @@ If, for any reason, the cluster creation or update process fails, you can restar
### Test classes
-There are four kind of tests: unit, integration, e2e, and expensive.
+There are four kinds of tests: unit, integration, e2e, and expensive.
Each of them covers specific use cases depending on the speed, cost, and dependencies at play in a given scenario.
-Anything that uses i/o should be marked as integration, with the only expection of local files and folders: any test
+Anything that uses i/o should be marked as integration, with the only expectation of local files and folders: any test
that uses the local filesystem and nothing more can be marked as 'unit'. This is made for convenience and it's open to
change in the future should we decide to refactor the code to better isolate that kind of i/o from the logic of the tool.
diff --git a/cmd/apply.go b/cmd/apply.go
index 7da3a7eca..8dfbdc859 100644
--- a/cmd/apply.go
+++ b/cmd/apply.go
@@ -8,7 +8,9 @@ import (
"errors"
"fmt"
"os"
+ "os/signal"
"path/filepath"
+ "syscall"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -20,6 +22,7 @@ import (
"github.com/sighupio/furyctl/internal/cluster"
"github.com/sighupio/furyctl/internal/config"
"github.com/sighupio/furyctl/internal/git"
+ "github.com/sighupio/furyctl/internal/lockfile"
cobrax "github.com/sighupio/furyctl/internal/x/cobra"
execx "github.com/sighupio/furyctl/internal/x/exec"
"github.com/sighupio/furyctl/pkg/dependencies"
@@ -59,10 +62,14 @@ type ClusterCmdFlags struct {
UpgradePathLocation string
UpgradeNode string
DistroPatchesLocation string
+ PostApplyPhases []string
ClusterSkipsCmdFlags
}
-var ErrDownloadDependenciesFailed = errors.New("dependencies download failed")
+var (
+ ErrDownloadDependenciesFailed = errors.New("dependencies download failed")
+ ErrPhaseInvalid = errors.New("phase is not valid")
+)
func NewApplyCmd() *cobra.Command {
var cmdEvent analytics.Event
@@ -167,6 +174,42 @@ func NewApplyCmd() *cobra.Command {
DryRun: flags.DryRun,
})
+ lockFileHandler := lockfile.NewLockFile(res.MinimalConf.Metadata.Name)
+ sigs := make(chan os.Signal, 1)
+
+ go func() {
+ <-sigs
+
+ if lockFileHandler != nil {
+ logrus.Debugf("Removing lock file %s", lockFileHandler.Path)
+
+ if err := lockFileHandler.Remove(); err != nil {
+ logrus.Errorf("error while removing lock file: %v", err)
+ }
+ }
+
+ os.Exit(1) //nolint:revive // ignore error
+ }()
+
+ signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+
+ err = lockFileHandler.Verify()
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while verifying lock file: %w", err)
+ }
+
+ err = lockFileHandler.Create()
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while creating lock file: %w", err)
+ }
+ defer lockFileHandler.Remove() //nolint:errcheck // ignore error
+
basePath := filepath.Join(outDir, ".furyctl", res.MinimalConf.Metadata.Name)
// Init second half of collaborators.
@@ -236,6 +279,7 @@ func NewApplyCmd() *cobra.Command {
flags.Upgrade,
flags.UpgradePathLocation,
flags.UpgradeNode,
+ flags.PostApplyPhases,
)
if err != nil {
cmdEvent.AddErrorMessage(err)
@@ -328,6 +372,12 @@ func getCreateClusterCmdFlags() (ClusterCmdFlags, error) {
)
}
+ postApplyPhases := viper.GetStringSlice("post-apply-phases")
+
+ if err := validatePostApplyPhasesFlag(postApplyPhases); err != nil {
+ return ClusterCmdFlags{}, fmt.Errorf("%w: %s %w", ErrParsingFlag, "post-apply-phases", err)
+ }
+
return ClusterCmdFlags{
Debug: viper.GetBool("debug"),
FuryctlPath: viper.GetString("config"),
@@ -350,9 +400,20 @@ func getCreateClusterCmdFlags() (ClusterCmdFlags, error) {
UpgradeNode: upgradeNode,
DistroPatchesLocation: viper.GetString("distro-patches"),
ClusterSkipsCmdFlags: skips,
+ PostApplyPhases: postApplyPhases,
}, nil
}
+func validatePostApplyPhasesFlag(phases []string) error {
+ for _, phase := range phases {
+ if err := cluster.ValidateMainPhases(phase); err != nil {
+ return fmt.Errorf("%w: %s", ErrPhaseInvalid, phase)
+ }
+ }
+
+ return nil
+}
+
func setupCreateClusterCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP(
"config",
@@ -446,6 +507,12 @@ func setupCreateClusterCmdFlags(cmd *cobra.Command) {
"WARNING: furyctl won't ask for confirmation and will proceed applying upgrades and reducers. Options are: all, upgrades, migrations, pods-running-check",
)
+ cmd.Flags().StringSlice(
+ "post-apply-phases",
+ []string{},
+ "Phases to run after the apply command. Options are: infrastructure, kubernetes, distribution, plugins",
+ )
+
cmd.Flags().Int(
"timeout",
3600, //nolint:mnd,revive // ignore magic number linters
diff --git a/cmd/create.go b/cmd/create.go
index da240be43..43735e980 100644
--- a/cmd/create.go
+++ b/cmd/create.go
@@ -33,6 +33,7 @@ func NewCreateCmd() *cobra.Command {
createCmd.AddCommand(NewClusterCmd())
createCmd.AddCommand(create.NewConfigCmd())
+ createCmd.AddCommand(create.NewPKICmd())
return createCmd
}
diff --git a/cmd/create/pki.go b/cmd/create/pki.go
new file mode 100644
index 000000000..ae838c706
--- /dev/null
+++ b/cmd/create/pki.go
@@ -0,0 +1,151 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package create
+
+import (
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "net"
+
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+ "github.com/spf13/viper"
+ certutil "k8s.io/client-go/util/cert"
+ pki "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
+
+ "github.com/sighupio/furyctl/internal/analytics"
+ "github.com/sighupio/furyctl/internal/app"
+ "github.com/sighupio/furyctl/internal/clusterpki"
+ cobrax "github.com/sighupio/furyctl/internal/x/cobra"
+)
+
+func NewPki(etcd, controlplane bool, pkiPath string) error {
+ var (
+ err error
+ msg error
+ data clusterpki.ClusterPKI
+
+ cert = certutil.Config{
+ CommonName: "SIGHUP s.r.l. Server",
+ Organization: []string{"SIGHUP s.r.l."},
+ AltNames: certutil.AltNames{DNSNames: []string{}, IPs: []net.IP{}},
+ Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ }
+ certConfig = pki.CertConfig{
+ Config: cert,
+ EncryptionAlgorithm: "",
+ }
+ )
+
+ data.Path = pkiPath
+ data.CertConfig = certConfig
+
+ switch {
+ default:
+ logrus.Debug("creating PKI for etcd and Kubernetes control plane")
+
+ etcd := clusterpki.Etcd{ClusterPKI: data}
+ cp := clusterpki.ControlPlanePKI{ClusterPKI: data}
+
+ err = etcd.Create()
+ if err != nil {
+ msg = fmt.Errorf("got error while creating etcd PKI: %w", err)
+ }
+
+ err = cp.Create()
+ if err != nil {
+ msg = fmt.Errorf("got error while creating control plane PKI: %w", err)
+ }
+
+ return msg
+
+ case etcd:
+ logrus.Debug("creating PKI for etcd")
+
+ etcd := clusterpki.Etcd{ClusterPKI: data}
+
+ err = etcd.Create()
+ if err != nil {
+ return fmt.Errorf("creating PKI for etcd failed: %w", err)
+ }
+
+ case controlplane:
+ logrus.Debug("creating PKI for Kubernetes control plane")
+
+ cp := clusterpki.ControlPlanePKI{ClusterPKI: data}
+
+ err := cp.Create()
+ if err != nil {
+ return fmt.Errorf("creating PKI for etcd failed: %w", err)
+ }
+ }
+
+ return errors.ErrUnsupported
+}
+
+func NewPKICmd() *cobra.Command {
+ var cmdEvent analytics.Event
+
+ pkiCmd := &cobra.Command{
+ Use: "pki",
+ Short: "Creates the Public Key infrastructure files needed.",
+ Long: `Creates the Public Key infrastructure files needed (CA, certificates, keys, etc.) by a Kubernetes cluster and its etcd database.
+ You can limit the creation of the PKI to just etcd or just Kubernetes using the flags, if not specified the command will create the PKI for both of them.`,
+ PreRun: func(cmd *cobra.Command, _ []string) {
+ cmdEvent = analytics.NewCommandEvent(cobrax.GetFullname(cmd))
+
+ if err := viper.BindPFlags(cmd.Flags()); err != nil {
+ logrus.Fatalf("error while binding flags: %v", err)
+ }
+ },
+ RunE: func(_ *cobra.Command, _ []string) error {
+ ctn := app.GetContainerInstance()
+
+ tracker := ctn.Tracker()
+ defer tracker.Flush()
+
+ // Get flags
+ // maybe we could get this path from the furyctl.yaml file.
+ pkiPath := viper.GetString("path")
+ etcd := viper.GetBool("etcd")
+ controlplane := viper.GetBool("controlplane")
+
+ if err := NewPki(etcd, controlplane, pkiPath); err != nil {
+ cmdEvent.AddErrorMessage(err)
+
+ return fmt.Errorf("PKI creation failed with error: %w", err)
+ }
+
+ cmdEvent.AddSuccessMessage("PKI files successfully created at:" + pkiPath)
+ tracker.Track(cmdEvent)
+
+ return nil
+ },
+ }
+
+ pkiCmd.Flags().StringP(
+ "path",
+ "p",
+ "pki",
+ "path where to save the created PKI files. One subfolder will be created for the control plane files and another one for the etcd files.",
+ )
+
+ pkiCmd.Flags().BoolP(
+ "etcd",
+ "e",
+ false,
+ "create PKI only for etcd",
+ )
+
+ pkiCmd.Flags().BoolP(
+ "controlplane",
+ "c",
+ false,
+ "create PKI only for the Kubernetes control plane components",
+ )
+
+ return pkiCmd
+}
diff --git a/cmd/delete/cluster.go b/cmd/delete/cluster.go
index 1f943098c..eaf4fe5bd 100644
--- a/cmd/delete/cluster.go
+++ b/cmd/delete/cluster.go
@@ -9,7 +9,9 @@ import (
"errors"
"fmt"
"os"
+ "os/signal"
"path/filepath"
+ "syscall"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -20,6 +22,7 @@ import (
"github.com/sighupio/furyctl/internal/cluster"
"github.com/sighupio/furyctl/internal/config"
"github.com/sighupio/furyctl/internal/git"
+ "github.com/sighupio/furyctl/internal/lockfile"
cobrax "github.com/sighupio/furyctl/internal/x/cobra"
execx "github.com/sighupio/furyctl/internal/x/exec"
iox "github.com/sighupio/furyctl/internal/x/io"
@@ -158,6 +161,42 @@ func NewClusterCmd() *cobra.Command {
DryRun: flags.DryRun,
})
+ lockFileHandler := lockfile.NewLockFile(res.MinimalConf.Metadata.Name)
+ sigs := make(chan os.Signal, 1)
+
+ go func() {
+ <-sigs
+
+ if lockFileHandler != nil {
+ logrus.Debugf("Removing lock file %s", lockFileHandler.Path)
+
+ if err := lockFileHandler.Remove(); err != nil {
+ logrus.Errorf("error while removing lock file: %v", err)
+ }
+ }
+
+ os.Exit(1) //nolint:revive // ignore exit code
+ }()
+
+ signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+
+ err = lockFileHandler.Verify()
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while verifying lock file: %w", err)
+ }
+
+ err = lockFileHandler.Create()
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while creating lock file: %w", err)
+ }
+ defer lockFileHandler.Remove() //nolint:errcheck // ignore error
+
basePath := filepath.Join(outDir, ".furyctl", res.MinimalConf.Metadata.Name)
// Init second half of collaborators.
diff --git a/cmd/diff.go b/cmd/diff.go
index a056da374..de3c999dc 100644
--- a/cmd/diff.go
+++ b/cmd/diff.go
@@ -257,6 +257,7 @@ func getPhasePath(
true,
upgradePathLocation,
"",
+ []string{},
)
if err != nil {
return "", fmt.Errorf("error while initializing cluster creator: %w", err)
diff --git a/cmd/renew.go b/cmd/renew.go
new file mode 100644
index 000000000..c88c696bd
--- /dev/null
+++ b/cmd/renew.go
@@ -0,0 +1,22 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/sighupio/furyctl/cmd/renew"
+)
+
+func NewRenewCmd() *cobra.Command {
+ renewCmd := &cobra.Command{
+ Use: "renew",
+ Short: "Renew a resource (e.g. certificates) of a cluster",
+ }
+
+ renewCmd.AddCommand(renew.NewCertificatesCmd())
+
+ return renewCmd
+}
diff --git a/cmd/renew/certificates.go b/cmd/renew/certificates.go
new file mode 100644
index 000000000..fbc6aae9e
--- /dev/null
+++ b/cmd/renew/certificates.go
@@ -0,0 +1,224 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package renew
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path"
+
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+ "github.com/spf13/viper"
+
+ "github.com/sighupio/furyctl/internal/analytics"
+ "github.com/sighupio/furyctl/internal/app"
+ "github.com/sighupio/furyctl/internal/cluster"
+ "github.com/sighupio/furyctl/internal/config"
+ "github.com/sighupio/furyctl/internal/git"
+ cobrax "github.com/sighupio/furyctl/internal/x/cobra"
+ execx "github.com/sighupio/furyctl/internal/x/exec"
+ "github.com/sighupio/furyctl/pkg/dependencies"
+ dist "github.com/sighupio/furyctl/pkg/distribution"
+ netx "github.com/sighupio/furyctl/pkg/x/net"
+)
+
+var ErrDownloadDependenciesFailed = errors.New("dependencies download failed")
+
+func NewCertificatesCmd() *cobra.Command {
+ var cmdEvent analytics.Event
+
+ certificatesCmd := &cobra.Command{
+ Use: "certificates",
+ Short: "Renew certificates of a cluster",
+ PreRun: func(cmd *cobra.Command, _ []string) {
+ cmdEvent = analytics.NewCommandEvent(cobrax.GetFullname(cmd))
+
+ if err := viper.BindPFlags(cmd.Flags()); err != nil {
+ logrus.Fatalf("error while binding flags: %v", err)
+ }
+ },
+ RunE: func(_ *cobra.Command, _ []string) error {
+ ctn := app.GetContainerInstance()
+
+ tracker := ctn.Tracker()
+ tracker.Flush()
+
+ // Get flags.
+ debug := viper.GetBool("debug")
+ binPath := viper.GetString("bin-path")
+ furyctlPath := viper.GetString("config")
+ outDir := viper.GetString("outdir")
+ distroLocation := viper.GetString("distro-location")
+ gitProtocol := viper.GetString("git-protocol")
+ skipDepsDownload := viper.GetBool("skip-deps-download")
+ skipDepsValidation := viper.GetBool("skip-deps-validation")
+
+ // Get Current dir.
+ logrus.Debug("Getting current directory path...")
+
+ currentDir, err := os.Getwd()
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while getting current directory: %w", err)
+ }
+
+ // Get home dir.
+ logrus.Debug("Getting Home directory path...")
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while getting user home directory: %w", err)
+ }
+
+ if binPath == "" {
+ binPath = path.Join(homeDir, ".furyctl", "bin")
+ }
+
+ parsedGitProtocol := (git.Protocol)(gitProtocol)
+
+ if outDir == "" {
+ outDir = currentDir
+ }
+
+ // Init packages.
+ execx.Debug = debug
+
+ executor := execx.NewStdExecutor()
+
+ distrodl := &dist.Downloader{}
+ depsvl := dependencies.NewValidator(executor, binPath, furyctlPath, false)
+
+ // Init first half of collaborators.
+ client := netx.NewGoGetterClient()
+
+ if distroLocation == "" {
+ distrodl = dist.NewCachingDownloader(client, outDir, parsedGitProtocol, "")
+ } else {
+ distrodl = dist.NewDownloader(client, parsedGitProtocol, "")
+ }
+
+ // Validate base requirements.
+ if err := depsvl.ValidateBaseReqs(); err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while validating requirements: %w", err)
+ }
+
+ // Download the distribution.
+ logrus.Info("Downloading distribution...")
+
+ res, err := distrodl.Download(distroLocation, furyctlPath)
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while downloading distribution: %w", err)
+ }
+
+ basePath := path.Join(outDir, ".furyctl", res.MinimalConf.Metadata.Name)
+
+ // Init second half of collaborators.
+ depsdl := dependencies.NewCachingDownloader(client, homeDir, basePath, binPath, parsedGitProtocol)
+
+ // Validate the furyctl.yaml file.
+ logrus.Info("Validating configuration file...")
+ if err := config.Validate(furyctlPath, res.RepoPath); err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while validating configuration file: %w", err)
+ }
+
+ // Download the dependencies.
+ if !skipDepsDownload {
+ logrus.Info("Downloading dependencies...")
+ if _, err := depsdl.DownloadTools(res.DistroManifest); err != nil {
+ cmdEvent.AddErrorMessage(ErrDownloadDependenciesFailed)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("%w: %v", ErrDownloadDependenciesFailed, err)
+ }
+ }
+
+ // Validate the dependencies, unless explicitly told to skip it.
+ if !skipDepsValidation {
+ logrus.Info("Validating dependencies...")
+ if err := depsvl.Validate(res); err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while validating dependencies: %w", err)
+ }
+ }
+
+ renewer, err := cluster.NewCertificatesRenewer(res.MinimalConf, res.DistroManifest, res.RepoPath, furyctlPath, outDir)
+ if err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while creating the certificates renewer: %w", err)
+ }
+
+ if err := renewer.Renew(); err != nil {
+ cmdEvent.AddErrorMessage(err)
+ tracker.Track(cmdEvent)
+
+ return fmt.Errorf("error while renewing certificates: %w", err)
+ }
+
+ logrus.Infof("Certificates successfully renewed")
+
+ cmdEvent.AddSuccessMessage("certificates successfully renewed")
+ tracker.Track(cmdEvent)
+
+ return nil
+ },
+ }
+
+ certificatesCmd.Flags().StringP(
+ "bin-path",
+ "b",
+ "",
+ "Path to the folder where all the dependencies' binaries are installed",
+ )
+
+ certificatesCmd.Flags().StringP(
+ "config",
+ "c",
+ "furyctl.yaml",
+ "Path to the configuration file",
+ )
+
+ certificatesCmd.Flags().StringP(
+ "distro-location",
+ "",
+ "",
+ "Location where to download schemas, defaults and the distribution manifests from. "+
+ "It can either be a local path (eg: /path/to/fury/distribution) or "+
+ "a remote URL (eg: git::git@github.com:sighupio/fury-distribution?depth=1&ref=BRANCH_NAME). "+
+ "Any format supported by hashicorp/go-getter can be used.",
+ )
+
+ certificatesCmd.Flags().Bool(
+ "skip-deps-download",
+ false,
+ "Skip downloading the binaries",
+ )
+
+ certificatesCmd.Flags().Bool(
+ "skip-deps-validation",
+ false,
+ "Skip validating dependencies",
+ )
+
+ return certificatesCmd
+}
diff --git a/cmd/root.go b/cmd/root.go
index 84c214430..b683593df 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -233,6 +233,7 @@ func NewRootCmd() *RootCommand {
rootCmd.AddCommand(NewLegacyCmd())
rootCmd.AddCommand(NewValidateCmd())
rootCmd.AddCommand(NewVersionCmd())
+ rootCmd.AddCommand(NewRenewCmd())
return rootCmd
}
diff --git a/configs/upgrades/ekscluster/1.27.6-1.27.7/pre-distribution.sh.tpl b/configs/upgrades/ekscluster/1.27.6-1.27.7/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/ekscluster/1.27.6-1.27.7/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/ekscluster/1.27.7-1.28.2/pre-distribution.sh.tpl b/configs/upgrades/ekscluster/1.27.7-1.28.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/ekscluster/1.27.7-1.28.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/ekscluster/1.27.7-1.28.2/pre-kubernetes.sh.tpl b/configs/upgrades/ekscluster/1.27.7-1.28.2/pre-kubernetes.sh.tpl
new file mode 100644
index 000000000..12e984f66
--- /dev/null
+++ b/configs/upgrades/ekscluster/1.27.7-1.28.2/pre-kubernetes.sh.tpl
@@ -0,0 +1,20 @@
+#!/usr/bin/env sh
+
+set -e
+
+{{- if index .spec "kubernetes" }}
+
+## master upgrades - only one at a time
+{{- range $h := .spec.kubernetes.masters.hosts }}
+ansible-playbook 55.upgrade-control-plane.yml --limit "{{ $h.name }}" --become
+{{- end }}
+
+{{- if ne .upgrade.skipNodesUpgrade true }}
+{{- range $n := .spec.kubernetes.nodes }}
+ {{- range $h := $n.hosts }}
+ansible-playbook 56.upgrade-worker-nodes.yml --limit "{{ $h.name }}"
+ {{- end }}
+{{- end }}
+{{- end }}
+
+{{- end }}
diff --git a/configs/upgrades/ekscluster/1.28.1-1.28.2/pre-distribution.sh.tpl b/configs/upgrades/ekscluster/1.28.1-1.28.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/ekscluster/1.28.1-1.28.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/ekscluster/1.28.2-1.29.2/pre-distribution.sh.tpl b/configs/upgrades/ekscluster/1.28.2-1.29.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/ekscluster/1.28.2-1.29.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/ekscluster/1.28.2-1.29.2/pre-kubernetes.sh.tpl b/configs/upgrades/ekscluster/1.28.2-1.29.2/pre-kubernetes.sh.tpl
new file mode 100644
index 000000000..12e984f66
--- /dev/null
+++ b/configs/upgrades/ekscluster/1.28.2-1.29.2/pre-kubernetes.sh.tpl
@@ -0,0 +1,20 @@
+#!/usr/bin/env sh
+
+set -e
+
+{{- if index .spec "kubernetes" }}
+
+## master upgrades - only one at a time
+{{- range $h := .spec.kubernetes.masters.hosts }}
+ansible-playbook 55.upgrade-control-plane.yml --limit "{{ $h.name }}" --become
+{{- end }}
+
+{{- if ne .upgrade.skipNodesUpgrade true }}
+{{- range $n := .spec.kubernetes.nodes }}
+ {{- range $h := $n.hosts }}
+ansible-playbook 56.upgrade-worker-nodes.yml --limit "{{ $h.name }}"
+ {{- end }}
+{{- end }}
+{{- end }}
+
+{{- end }}
diff --git a/configs/upgrades/ekscluster/1.29.1-1.29.2/pre-distribution.sh.tpl b/configs/upgrades/ekscluster/1.29.1-1.29.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/ekscluster/1.29.1-1.29.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/kfddistribution/1.27.6-1.27.7/pre-distribution.sh.tpl b/configs/upgrades/kfddistribution/1.27.6-1.27.7/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/kfddistribution/1.27.6-1.27.7/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/kfddistribution/1.27.7-1.28.2/pre-distribution.sh.tpl b/configs/upgrades/kfddistribution/1.27.7-1.28.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/kfddistribution/1.27.7-1.28.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/kfddistribution/1.28.1-1.28.2/pre-distribution.sh.tpl b/configs/upgrades/kfddistribution/1.28.1-1.28.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/kfddistribution/1.28.1-1.28.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/kfddistribution/1.28.2-1.29.2/pre-distribution.sh.tpl b/configs/upgrades/kfddistribution/1.28.2-1.29.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/kfddistribution/1.28.2-1.29.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/kfddistribution/1.29.1-1.29.2/pre-distribution.sh.tpl b/configs/upgrades/kfddistribution/1.29.1-1.29.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/kfddistribution/1.29.1-1.29.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/onpremises/1.27.6-1.27.7/pre-distribution.sh.tpl b/configs/upgrades/onpremises/1.27.6-1.27.7/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/onpremises/1.27.6-1.27.7/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/onpremises/1.27.7-1.28.2/pre-distribution.sh.tpl b/configs/upgrades/onpremises/1.27.7-1.28.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/onpremises/1.27.7-1.28.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/onpremises/1.27.7-1.28.2/pre-kubernetes.sh.tpl b/configs/upgrades/onpremises/1.27.7-1.28.2/pre-kubernetes.sh.tpl
new file mode 100644
index 000000000..12e984f66
--- /dev/null
+++ b/configs/upgrades/onpremises/1.27.7-1.28.2/pre-kubernetes.sh.tpl
@@ -0,0 +1,20 @@
+#!/usr/bin/env sh
+
+set -e
+
+{{- if index .spec "kubernetes" }}
+
+## master upgrades - only one at a time
+{{- range $h := .spec.kubernetes.masters.hosts }}
+ansible-playbook 55.upgrade-control-plane.yml --limit "{{ $h.name }}" --become
+{{- end }}
+
+{{- if ne .upgrade.skipNodesUpgrade true }}
+{{- range $n := .spec.kubernetes.nodes }}
+ {{- range $h := $n.hosts }}
+ansible-playbook 56.upgrade-worker-nodes.yml --limit "{{ $h.name }}"
+ {{- end }}
+{{- end }}
+{{- end }}
+
+{{- end }}
diff --git a/configs/upgrades/onpremises/1.28.1-1.28.2/pre-distribution.sh.tpl b/configs/upgrades/onpremises/1.28.1-1.28.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/onpremises/1.28.1-1.28.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/onpremises/1.28.2-1.29.2/pre-distribution.sh.tpl b/configs/upgrades/onpremises/1.28.2-1.29.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/onpremises/1.28.2-1.29.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/configs/upgrades/onpremises/1.28.2-1.29.2/pre-kubernetes.sh.tpl b/configs/upgrades/onpremises/1.28.2-1.29.2/pre-kubernetes.sh.tpl
new file mode 100644
index 000000000..12e984f66
--- /dev/null
+++ b/configs/upgrades/onpremises/1.28.2-1.29.2/pre-kubernetes.sh.tpl
@@ -0,0 +1,20 @@
+#!/usr/bin/env sh
+
+set -e
+
+{{- if index .spec "kubernetes" }}
+
+## master upgrades - only one at a time
+{{- range $h := .spec.kubernetes.masters.hosts }}
+ansible-playbook 55.upgrade-control-plane.yml --limit "{{ $h.name }}" --become
+{{- end }}
+
+{{- if ne .upgrade.skipNodesUpgrade true }}
+{{- range $n := .spec.kubernetes.nodes }}
+ {{- range $h := $n.hosts }}
+ansible-playbook 56.upgrade-worker-nodes.yml --limit "{{ $h.name }}"
+ {{- end }}
+{{- end }}
+{{- end }}
+
+{{- end }}
diff --git a/configs/upgrades/onpremises/1.29.1-1.29.2/pre-distribution.sh.tpl b/configs/upgrades/onpremises/1.29.1-1.29.2/pre-distribution.sh.tpl
new file mode 100644
index 000000000..2eeeb36a4
--- /dev/null
+++ b/configs/upgrades/onpremises/1.29.1-1.29.2/pre-distribution.sh.tpl
@@ -0,0 +1,10 @@
+#!/usr/bin/env sh
+
+set -e
+
+kubectlbin="{{ .paths.kubectl }}"
+
+# Remove some validating webhooks during the upgrade
+{{- if eq .spec.distribution.modules.policy.type "gatekeeper" }}
+$kubectlbin delete --ignore-not-found=true validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
+{{- end }}
diff --git a/docs/COMPATIBILITY_MATRIX.md b/docs/COMPATIBILITY_MATRIX.md
index bd00e3e24..bb47fcd65 100644
--- a/docs/COMPATIBILITY_MATRIX.md
+++ b/docs/COMPATIBILITY_MATRIX.md
@@ -8,27 +8,29 @@ Note: Always use the latest `furyctl` version, we make sure that is compatible w
- Versions < 0.27.5 do not work with the OnPremises provider, we fixed this issue in 0.27.5, so we recommend using this version or later.
-| Furyctl / KFD | 1.29.1 | 1.29.0 | 1.28.1 | 1.28.0 | 1.27.6 | 1.27.5 | 1.27.4 | 1.27.3 | 1.27.2 | 1.27.1 | 1.27.0 | 1.26.6 | 1.26.5 | 1.26.4 | 1.26.3 | 1.25.10 | 1.25.9 | 1.25.8 |
-| ------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
-| 0.29.3 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| 0.29.2 | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: |
-| 0.29.1 | | :warning: | | :warning: | | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: |
-| 0.29.0 | | :white_check_mark: | | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| 0.28.0 | | | | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| 0.27.8 | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| 0.27.7 | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| 0.27.6 | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| 0.27.5 | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| 0.27.4 | | | | | | | :warning: | :warning: | :warning: | :warning: | :warning: | | :warning: | :warning: | :warning: | :warning: | :warning: | :warning:
-| 0.27.3 | | | | | | | :warning: | :warning: | :warning: | :warning: | :warning: | | :warning: | :warning: | :warning: | :warning: | :warning: | :warning:
-| 0.27.2 | | | | | | | | :warning: | :warning: | :warning: | | | :warning: | :warning: | | :warning: | :warning: | :warning:
-| 0.27.1 | | | | | | | | | :warning: | :warning: | | | :warning: | :warning: | | :warning: | :warning: | :warning:
-| 0.27.0 | | | | | | | | | :warning: | :warning: | | | :warning: | :warning: | | :warning: | :warning: | :warning:
+| Furyctl / KFD | 1.29.2 | 1.29.1 | 1.29.0 | 1.28.2 | 1.28.1 | 1.28.0 | 1.27.7 | 1.27.6 | 1.27.5 | 1.27.4 | 1.27.3 | 1.27.2 | 1.27.1 | 1.27.0 | 1.26.6 | 1.26.5 | 1.26.4 | 1.26.3 | 1.25.10 | 1.25.9 | 1.25.8 |
+| ------------- | ------------- | ------------- | ------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
+| 0.29.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.29.3 | | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.29.2 | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: |
+| 0.29.1 | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: | :warning: |
+| 0.29.0 | | | :white_check_mark: | | | :white_check_mark: | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.28.0 | | | | | | :white_check_mark: | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.27.8 | | | | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.27.7 | | | | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.27.6 | | | | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.27.5 | | | | | | | | | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| 0.27.4 | | | | | | | | | | :warning: | :warning: | :warning: | :warning: | :warning: | | :warning: | :warning: | :warning: | :warning: | :warning: | :warning:
+| 0.27.3 | | | | | | | | | | :warning: | :warning: | :warning: | :warning: | :warning: | | :warning: | :warning: | :warning: | :warning: | :warning: | :warning:
+| 0.27.2 | | | | | | | | | | | :warning: | :warning: | :warning: | | | :warning: | :warning: | | :warning: | :warning: | :warning:
+| 0.27.1 | | | | | | | | | | | | :warning: | :warning: | | | :warning: | :warning: | | :warning: | :warning: | :warning:
+| 0.27.0 | | | | | | | | | | | | :warning: | :warning: | | | :warning: | :warning: | | :warning: | :warning: | :warning:
## Furyctl and Providers compatibility
| Furyctl / Providers | EKSCluster | KFDDistribution | OnPremises |
| ------------------- | ------------------ | ------------------ | ------------------ |
+| 0.29.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| 0.29.3 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| 0.29.2 | :x: | :x: | :x: |
| 0.29.1 | :x: | :x: | :x: |
diff --git a/go.mod b/go.mod
index 77c44dade..d4f41b5d3 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
github.com/r3labs/diff/v3 v3.0.1
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
github.com/shirou/gopsutil/v3 v3.24.1
- github.com/sighupio/fury-distribution v1.29.2-0.20240717134128-30a1206f46d6
+ github.com/sighupio/fury-distribution v1.29.2
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.18.2
@@ -29,25 +29,37 @@ require (
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
+ k8s.io/client-go v0.29.7
+ k8s.io/kubernetes v1.29.7
)
require (
- github.com/emicklei/go-restful/v3 v3.10.2 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/blang/semver/v4 v4.0.0 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
- github.com/google/gnostic v0.6.9 // indirect
+ github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
+ github.com/gorilla/websocket v1.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+ github.com/prometheus/client_golang v1.16.0 // indirect
+ github.com/prometheus/client_model v0.4.0 // indirect
+ github.com/prometheus/common v0.44.0 // indirect
+ github.com/prometheus/procfs v0.10.1 // indirect
github.com/vladimirvivien/gexe v0.2.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect
@@ -55,15 +67,16 @@ require (
go.opentelemetry.io/otel/metric v1.23.0 // indirect
go.opentelemetry.io/otel/trace v1.23.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- k8s.io/api v0.27.4 // indirect
- k8s.io/apimachinery v0.27.4 // indirect
- k8s.io/client-go v0.27.4 // indirect
- k8s.io/klog/v2 v2.100.1 // indirect
- k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
- k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
+ k8s.io/api v0.29.7 // indirect
+ k8s.io/apimachinery v0.29.7 // indirect
+ k8s.io/cluster-bootstrap v0.0.0 // indirect
+ k8s.io/component-base v0.27.2 // indirect
+ k8s.io/klog/v2 v2.120.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
+ k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/controller-runtime v0.15.1 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
- sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
@@ -89,7 +102,7 @@ require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
- github.com/golang/protobuf v1.5.3 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
github.com/google/pprof v0.0.0-20240130152714-0ed6a68c8d9e // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
@@ -144,7 +157,7 @@ require (
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.17.0 // indirect
+ golang.org/x/tools v0.18.0 // indirect
google.golang.org/api v0.162.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect
@@ -155,3 +168,38 @@ require (
gopkg.in/ini.v1 v1.67.0 // indirect
sigs.k8s.io/e2e-framework v0.3.0
)
+
+// Pinned to kubernetes-1.29.7, thanks to https://github.com/kubernetes/kubernetes/issues/79384#issuecomment-521493597
+// k8s.io/api v0.x.y -> Kubernetes v1.x.y
+replace (
+ k8s.io/api => k8s.io/api v0.29.7
+ k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.29.7
+ k8s.io/apimachinery => k8s.io/apimachinery v0.29.7
+ k8s.io/apiserver => k8s.io/apiserver v0.29.7
+ k8s.io/cli-runtime => k8s.io/cli-runtime v0.29.7
+ k8s.io/client-go => k8s.io/client-go v0.29.7
+ k8s.io/cloud-provider => k8s.io/cloud-provider v0.29.7
+ k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.29.7
+ k8s.io/code-generator => k8s.io/code-generator v0.29.7
+ k8s.io/component-base => k8s.io/component-base v0.29.7
+ k8s.io/component-helpers => k8s.io/component-helpers v0.29.7
+ k8s.io/controller-manager => k8s.io/controller-manager v0.29.7
+ k8s.io/cri-api => k8s.io/cri-api v0.29.7
+ k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.29.7
+ k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.29.7
+ k8s.io/endpointslice => k8s.io/endpointslice v0.29.7
+ k8s.io/kms => k8s.io/kms v0.29.7
+ k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.29.7
+ k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.29.7
+ k8s.io/kube-proxy => k8s.io/kube-proxy v0.29.7
+ k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.29.7
+ k8s.io/kubectl => k8s.io/kubectl v0.29.7
+ k8s.io/kubelet => k8s.io/kubelet v0.29.7
+ k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.29.7
+ k8s.io/metrics => k8s.io/metrics v0.29.7
+ k8s.io/mount-utils => k8s.io/mount-utils v0.29.7
+ k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.29.7
+ k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.29.7
+ k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.29.7
+ k8s.io/sample-controller => k8s.io/sample-controller v0.29.7
+)
diff --git a/go.sum b/go.sum
index ee8712773..44f8a79ca 100644
--- a/go.sum
+++ b/go.sum
@@ -209,11 +209,11 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
+github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
+github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A=
github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE=
-github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -242,11 +242,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dukex/mixpanel v1.0.1 h1:IQ3qBjtgltF044jU9+i6MubdDdpc8PKpK9yvfawRgeE=
github.com/dukex/mixpanel v1.0.1/go.mod h1:080BDsRRMzAxViWT3OjlQaMW9nhaIEXDHHtGeDK60b8=
-github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
-github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
+github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -266,7 +265,6 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
@@ -277,7 +275,6 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -338,13 +335,13 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
-github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
+github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -414,6 +411,8 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
@@ -456,7 +455,6 @@ github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrD
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -506,6 +504,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
@@ -521,21 +521,21 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
-github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
-github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
+github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
-github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
-github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
-github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
-github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
+github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
+github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
+github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
+github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/r3labs/diff/v3 v3.0.1 h1:CBKqf3XmNRHXKmdU7mZP1w7TV0pDyVCis1AUHtA4Xtg=
github.com/r3labs/diff/v3 v3.0.1/go.mod h1:f1S9bourRbiM66NskseyUdo0fTmEE0qKrikYJX63dgo=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
-github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
@@ -552,8 +552,8 @@ github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/sighupio/fury-distribution v1.29.2-0.20240717134128-30a1206f46d6 h1:Sm2sPU/dxAHcBV7KIdvtsXkoJY4jolB5W0xW/REymjo=
-github.com/sighupio/fury-distribution v1.29.2-0.20240717134128-30a1206f46d6/go.mod h1:iYBnl0N/6zGPz3j3L2X6nzFC3nzNQtIkAzmaPfnO0zA=
+github.com/sighupio/fury-distribution v1.29.2 h1:pToy5BLFvCWEjhCDtnAqTEw0OFpgel/3VvzccT6bU0Y=
+github.com/sighupio/fury-distribution v1.29.2/go.mod h1:iYBnl0N/6zGPz3j3L2X6nzFC3nzNQtIkAzmaPfnO0zA=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@@ -570,7 +570,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
-github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -603,9 +602,6 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -639,8 +635,8 @@ go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6
go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI=
go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
-go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
+go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
@@ -729,7 +725,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@@ -940,8 +935,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
-golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
+golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
+golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1074,7 +1069,6 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
@@ -1178,7 +1172,6 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
@@ -1194,7 +1187,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1204,20 +1196,26 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs=
-k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y=
-k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo=
-k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ=
-k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
-k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
-k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
-k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
-k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
-k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
-k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
-k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
-k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/api v0.29.7 h1:Q2/thp7YYESgy0MGzxT9RvA/6doLJHBXSFH8GGLxSbc=
+k8s.io/api v0.29.7/go.mod h1:mPimdbyuIjwoLtBEVIGVUYb4BKOE+44XHt/n4IqKsLA=
+k8s.io/apiextensions-apiserver v0.29.7 h1:X62u7vUGfwW5rYJB5jkZDr0uV2XSyEHJRdxnfD5PaLs=
+k8s.io/apiextensions-apiserver v0.29.7/go.mod h1:JzBXxlZKKdtEYGr4yiN+s0eXheCTYgKDay8JXPfSGoQ=
+k8s.io/apimachinery v0.29.7 h1:ICXzya58Q7hyEEfnTrbmdfX1n1schSepX2KUfC2/ykc=
+k8s.io/apimachinery v0.29.7/go.mod h1:i3FJVwhvSp/6n8Fl4K97PJEP8C+MM+aoDq4+ZJBf70Y=
+k8s.io/client-go v0.29.7 h1:vTtiFrGBKlcBhxaeZC4eDrqui1e108nsTyue/KU63IY=
+k8s.io/client-go v0.29.7/go.mod h1:69BvVqdRozgR/9TP45u/oO0tfrdbP+I8RqrcCJQshzg=
+k8s.io/cluster-bootstrap v0.29.7 h1:e3bEQTIVdfSBm3akfsUIfGGePxWZbjjviSYGWoei4xU=
+k8s.io/cluster-bootstrap v0.29.7/go.mod h1:GqBhCNVZ9QWc/aQTroEO8yLXO6pq1k6SmD39ShTcIJk=
+k8s.io/component-base v0.29.7 h1:zXLJvZjvvDWdYmZCwZYk95E1Fd2oRXUz71mQukkRk5I=
+k8s.io/component-base v0.29.7/go.mod h1:ddLTpIrjazaRI1EG83M41GNcYEAdskuQmx4JOOSXCOg=
+k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
+k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
+k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
+k8s.io/kubernetes v1.29.7 h1:cC7YHkNIbHJ6kxjeN6cLZDU4wFxuymyB89NZl3rKI3Y=
+k8s.io/kubernetes v1.29.7/go.mod h1:28sDhcb87LX5z3GWAKYmLrhrifxi4W9bEWua4DRTIvk=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
@@ -1227,7 +1225,7 @@ sigs.k8s.io/e2e-framework v0.3.0 h1:eqQALBtPCth8+ulTs6lcPK7ytV5rZSSHJzQHZph4O7U=
sigs.k8s.io/e2e-framework v0.3.0/go.mod h1:C+ef37/D90Dc7Xq1jQnNbJYscrUGpxrWog9bx2KIa+c=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/internal/analytics/tracker.go b/internal/analytics/tracker.go
index c0c8e94eb..68648b967 100644
--- a/internal/analytics/tracker.go
+++ b/internal/analytics/tracker.go
@@ -110,6 +110,8 @@ func (a *Tracker) processEvents() {
if !ok {
logrus.Trace("Event processor stopped")
+ a.enable = false
+
break
}
@@ -118,7 +120,8 @@ func (a *Tracker) processEvents() {
switch e.(type) {
case StopEvent:
logrus.Trace("Stop event received, stopping event processor")
- a.close()
+
+ a.Disable()
return
diff --git a/internal/apis/kfd/v1alpha2/ekscluster/certificates_renewer.go b/internal/apis/kfd/v1alpha2/ekscluster/certificates_renewer.go
new file mode 100644
index 000000000..c606dcef2
--- /dev/null
+++ b/internal/apis/kfd/v1alpha2/ekscluster/certificates_renewer.go
@@ -0,0 +1,23 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ekscluster
+
+import (
+ "errors"
+
+ "github.com/sighupio/furyctl/internal/cluster"
+)
+
+var ErrRenewNotSupported = errors.New("you can't renew certificates for EKSCluster")
+
+type CertificatesRenewer struct{}
+
+func (*CertificatesRenewer) SetProperties(_ []cluster.CertificatesRenewerProperty) {}
+
+func (*CertificatesRenewer) SetProperty(_ string, _ any) {}
+
+func (*CertificatesRenewer) Renew() error {
+ return ErrRenewNotSupported
+}
diff --git a/internal/apis/kfd/v1alpha2/ekscluster/create/distribution.go b/internal/apis/kfd/v1alpha2/ekscluster/create/distribution.go
index de28d3f3e..b204ae804 100644
--- a/internal/apis/kfd/v1alpha2/ekscluster/create/distribution.go
+++ b/internal/apis/kfd/v1alpha2/ekscluster/create/distribution.go
@@ -377,6 +377,10 @@ func (d *Distribution) runReducers(
return nil
}
+func (d *Distribution) SetUpgrade(upgradeEnabled bool) {
+ d.upgrade.Enabled = upgradeEnabled
+}
+
func (d *Distribution) Stop() error {
errCh := make(chan error)
doneCh := make(chan bool)
diff --git a/internal/apis/kfd/v1alpha2/ekscluster/create/infrastructure.go b/internal/apis/kfd/v1alpha2/ekscluster/create/infrastructure.go
index 896a7956d..fc74dfeb1 100644
--- a/internal/apis/kfd/v1alpha2/ekscluster/create/infrastructure.go
+++ b/internal/apis/kfd/v1alpha2/ekscluster/create/infrastructure.go
@@ -215,6 +215,10 @@ func (i *Infrastructure) postInfrastructure(
return nil
}
+func (i *Infrastructure) SetUpgrade(upgradeEnabled bool) {
+ i.upgrade.Enabled = upgradeEnabled
+}
+
func (i *Infrastructure) Stop() error {
logrus.Debug("Stopping terraform...")
diff --git a/internal/apis/kfd/v1alpha2/ekscluster/create/kubernetes.go b/internal/apis/kfd/v1alpha2/ekscluster/create/kubernetes.go
index 71732b516..c391bc2ec 100644
--- a/internal/apis/kfd/v1alpha2/ekscluster/create/kubernetes.go
+++ b/internal/apis/kfd/v1alpha2/ekscluster/create/kubernetes.go
@@ -282,6 +282,10 @@ func (k *Kubernetes) postKubernetes(
return nil
}
+func (k *Kubernetes) SetUpgrade(upgradeEnabled bool) {
+ k.upgrade.Enabled = upgradeEnabled
+}
+
func (k *Kubernetes) Stop() error {
errCh := make(chan error)
doneCh := make(chan bool)
diff --git a/internal/apis/kfd/v1alpha2/ekscluster/creator.go b/internal/apis/kfd/v1alpha2/ekscluster/creator.go
index ea693b8ef..44fc3043c 100644
--- a/internal/apis/kfd/v1alpha2/ekscluster/creator.go
+++ b/internal/apis/kfd/v1alpha2/ekscluster/creator.go
@@ -60,6 +60,7 @@ type ClusterCreator struct {
force []string
upgrade bool
externalUpgradesPath string
+ postApplyPhases []string
}
type Phases struct {
@@ -158,6 +159,11 @@ func (v *ClusterCreator) SetProperty(name string, value any) {
if s, ok := value.(string); ok {
v.externalUpgradesPath = s
}
+
+ case cluster.CreatorPropertyPostApplyPhases:
+ if s, ok := value.([]string); ok {
+ v.postApplyPhases = s
+ }
}
}
@@ -637,6 +643,14 @@ func (v *ClusterCreator) allPhases(
return err
}
+ if len(v.postApplyPhases) > 0 {
+ logrus.Info("Executing extra phases...")
+
+ if err := v.extraPhases(phases, upgradeState, upgr); err != nil {
+ return fmt.Errorf("error while executing extra phases: %w", err)
+ }
+ }
+
if v.dryRun {
logrus.Info("Kubernetes Fury cluster created successfully (dry-run mode)")
@@ -670,6 +684,52 @@ func (v *ClusterCreator) allPhases(
return nil
}
+func (v *ClusterCreator) extraPhases(phases *Phases, upgradeState *upgrade.State, upgr *upgrade.Upgrade) error {
+ initialUpgrade := upgr.Enabled
+
+ defer func() {
+ upgr.Enabled = initialUpgrade
+ }()
+
+ for _, phase := range v.postApplyPhases {
+ switch phase {
+ case cluster.OperationPhaseInfrastructure:
+ phases.Infrastructure.SetUpgrade(false)
+
+ if err := phases.Infrastructure.Exec(StartFromFlagNotSet, upgradeState); err != nil {
+ return fmt.Errorf("error while executing post infrastructure phase: %w", err)
+ }
+
+ case cluster.OperationPhaseKubernetes:
+ phases.Kubernetes.SetUpgrade(false)
+
+ if err := phases.Kubernetes.Exec(StartFromFlagNotSet, upgradeState); err != nil {
+ return fmt.Errorf("error while executing post kubernetes phase: %w", err)
+ }
+
+ case cluster.OperationPhaseDistribution:
+ phases.Distribution.SetUpgrade(false)
+
+ if err := phases.Distribution.Exec(
+ reducers.Reducers{},
+ StartFromFlagNotSet,
+ upgradeState,
+ ); err != nil {
+ return fmt.Errorf("error while executing post distribution phase: %w", err)
+ }
+
+ case cluster.OperationPhasePlugins:
+ if distribution.HasFeature(v.kfdManifest, distribution.FeaturePlugins) {
+ if err := phases.Plugins.Exec(); err != nil {
+ return fmt.Errorf("error while executing plugins phase: %w", err)
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
func (v *ClusterCreator) allPhasesExec(
startFrom string,
phases *Phases,
diff --git a/internal/apis/kfd/v1alpha2/ekscluster/init.go b/internal/apis/kfd/v1alpha2/ekscluster/init.go
index 9893b728f..d2a5159b6 100644
--- a/internal/apis/kfd/v1alpha2/ekscluster/init.go
+++ b/internal/apis/kfd/v1alpha2/ekscluster/init.go
@@ -28,4 +28,12 @@ func init() {
"EKSCluster",
cluster.NewKubeconfigFactory[*KubeconfigGetter, private.EksclusterKfdV1Alpha2](&KubeconfigGetter{}),
)
+
+ cluster.RegisterCertificatesRenewerFactory(
+ "kfd.sighup.io/v1alpha2",
+ "EKSCluster",
+ cluster.NewCertificatesRenewerFactory[*CertificatesRenewer, private.EksclusterKfdV1Alpha2](
+ &CertificatesRenewer{},
+ ),
+ )
}
diff --git a/internal/apis/kfd/v1alpha2/kfddistribution/certificates_renewer.go b/internal/apis/kfd/v1alpha2/kfddistribution/certificates_renewer.go
new file mode 100644
index 000000000..88c9b033f
--- /dev/null
+++ b/internal/apis/kfd/v1alpha2/kfddistribution/certificates_renewer.go
@@ -0,0 +1,23 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package kfddistribution
+
+import (
+ "errors"
+
+ "github.com/sighupio/furyctl/internal/cluster"
+)
+
+var ErrRenewNotSupported = errors.New("you can't renew certificates for KFDDistribution")
+
+type CertificatesRenewer struct{}
+
+func (*CertificatesRenewer) SetProperties(_ []cluster.CertificatesRenewerProperty) {}
+
+func (*CertificatesRenewer) SetProperty(_ string, _ any) {}
+
+func (*CertificatesRenewer) Renew() error {
+ return ErrRenewNotSupported
+}
diff --git a/internal/apis/kfd/v1alpha2/kfddistribution/create/distribution.go b/internal/apis/kfd/v1alpha2/kfddistribution/create/distribution.go
index 5f5f04035..ba95e7fb9 100644
--- a/internal/apis/kfd/v1alpha2/kfddistribution/create/distribution.go
+++ b/internal/apis/kfd/v1alpha2/kfddistribution/create/distribution.go
@@ -364,6 +364,10 @@ func (d *Distribution) Stop() error {
return nil
}
+func (d *Distribution) SetUpgrade(upgradeEnabled bool) {
+ d.upgrade.Enabled = upgradeEnabled
+}
+
func (d *Distribution) runReducers(
rdcs reducers.Reducers,
cfg template.Config,
diff --git a/internal/apis/kfd/v1alpha2/kfddistribution/creator.go b/internal/apis/kfd/v1alpha2/kfddistribution/creator.go
index fe4a665c8..481c92746 100644
--- a/internal/apis/kfd/v1alpha2/kfddistribution/creator.go
+++ b/internal/apis/kfd/v1alpha2/kfddistribution/creator.go
@@ -49,6 +49,7 @@ type ClusterCreator struct {
force []string
upgrade bool
externalUpgradesPath string
+ postApplyPhases []string
}
func (c *ClusterCreator) SetProperties(props []cluster.CreatorProperty) {
@@ -127,6 +128,11 @@ func (c *ClusterCreator) SetProperty(name string, value any) {
if s, ok := value.(string); ok {
c.externalUpgradesPath = s
}
+
+ case cluster.CreatorPropertyPostApplyPhases:
+ if s, ok := value.([]string); ok {
+ c.postApplyPhases = s
+ }
}
}
@@ -366,6 +372,47 @@ func (c *ClusterCreator) allPhases(
}
}
+ if len(c.postApplyPhases) > 0 {
+ logrus.Info("Executing extra phases...")
+
+ if err := c.extraPhases(distributionPhase, pluginsPhase, upgradeState, upgr); err != nil {
+ return fmt.Errorf("error while executing extra phases: %w", err)
+ }
+ }
+
+ return nil
+}
+
+func (c *ClusterCreator) extraPhases(
+ distributionPhase upgrade.ReducersOperatorPhase[reducers.Reducers],
+ pluginsPhase *commcreate.Plugins,
+ upgradeState *upgrade.State,
+ upgr *upgrade.Upgrade,
+) error {
+ initialUpgrade := upgr.Enabled
+
+ defer func() {
+ upgr.Enabled = initialUpgrade
+ }()
+
+ for _, phase := range c.postApplyPhases {
+ switch phase {
+ case cluster.OperationPhaseDistribution:
+ distributionPhase.SetUpgrade(false)
+
+ if err := distributionPhase.Exec(reducers.Reducers{}, StartFromFlagNotSet, upgradeState); err != nil {
+ return fmt.Errorf("error while executing distribution phase: %w", err)
+ }
+
+ case cluster.OperationPhasePlugins:
+ if distribution.HasFeature(c.kfdManifest, distribution.FeaturePlugins) {
+ if err := pluginsPhase.Exec(); err != nil {
+ return fmt.Errorf("error while executing plugins phase: %w", err)
+ }
+ }
+ }
+ }
+
return nil
}
diff --git a/internal/apis/kfd/v1alpha2/kfddistribution/init.go b/internal/apis/kfd/v1alpha2/kfddistribution/init.go
index e592398a1..d0113dfae 100644
--- a/internal/apis/kfd/v1alpha2/kfddistribution/init.go
+++ b/internal/apis/kfd/v1alpha2/kfddistribution/init.go
@@ -28,4 +28,12 @@ func init() {
"KFDDistribution",
cluster.NewKubeconfigFactory[*KubeconfigGetter, public.KfddistributionKfdV1Alpha2](&KubeconfigGetter{}),
)
+
+ cluster.RegisterCertificatesRenewerFactory(
+ "kfd.sighup.io/v1alpha2",
+ "KFDDistribution",
+ cluster.NewCertificatesRenewerFactory[*CertificatesRenewer, public.KfddistributionKfdV1Alpha2](
+ &CertificatesRenewer{},
+ ),
+ )
}
diff --git a/internal/apis/kfd/v1alpha2/onpremises/certificates_renewer.go b/internal/apis/kfd/v1alpha2/onpremises/certificates_renewer.go
new file mode 100644
index 000000000..3a8ed987d
--- /dev/null
+++ b/internal/apis/kfd/v1alpha2/onpremises/certificates_renewer.go
@@ -0,0 +1,143 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package onpremises
+
+import (
+ "fmt"
+ "os"
+ "path"
+ "strings"
+
+ "github.com/sirupsen/logrus"
+
+ "github.com/sighupio/fury-distribution/pkg/apis/config"
+ "github.com/sighupio/fury-distribution/pkg/apis/onpremises/v1alpha2/public"
+ "github.com/sighupio/furyctl/internal/cluster"
+ "github.com/sighupio/furyctl/internal/tool/ansible"
+ execx "github.com/sighupio/furyctl/internal/x/exec"
+ "github.com/sighupio/furyctl/pkg/template"
+)
+
+type CertificatesRenewer struct {
+ *cluster.OperationPhase
+ furyctlConf public.OnpremisesKfdV1Alpha2
+ kfdManifest config.KFD
+ distroPath string
+ configPath string
+ outDir string
+}
+
+func (k *CertificatesRenewer) SetProperties(props []cluster.CertificatesRenewerProperty) {
+ for _, prop := range props {
+ k.SetProperty(prop.Name, prop.Value)
+ }
+
+ k.OperationPhase = &cluster.OperationPhase{}
+}
+
+func (k *CertificatesRenewer) SetProperty(name string, value any) {
+ lcName := strings.ToLower(name)
+
+ switch lcName {
+ case cluster.KubeconfigPropertyFuryctlConf:
+ if s, ok := value.(public.OnpremisesKfdV1Alpha2); ok {
+ k.furyctlConf = s
+ }
+
+ case cluster.KubeconfigPropertyConfigPath:
+ if s, ok := value.(string); ok {
+ k.configPath = s
+ }
+
+ case cluster.KubeconfigPropertyOutdir:
+ if s, ok := value.(string); ok {
+ k.outDir = s
+ }
+
+ case cluster.KubeconfigPropertyKfdManifest:
+ if s, ok := value.(config.KFD); ok {
+ k.kfdManifest = s
+ }
+
+ case cluster.KubeconfigPropertyDistroPath:
+ if s, ok := value.(string); ok {
+ k.distroPath = s
+ }
+ }
+}
+
+func (k *CertificatesRenewer) Renew() error {
+ logrus.Info("Renewing certificates...")
+
+ tmpDir, err := os.MkdirTemp("", "fury-certificates-renewer-*")
+ if err != nil {
+ return fmt.Errorf("error creating temporary directory: %w", err)
+ }
+
+ defer os.RemoveAll(tmpDir)
+
+ ansibleRunner := ansible.NewRunner(
+ execx.NewStdExecutor(),
+ ansible.Paths{
+ Ansible: "ansible",
+ AnsiblePlaybook: "ansible-playbook",
+ WorkDir: tmpDir,
+ },
+ )
+
+ furyctlMerger, err := k.CreateFuryctlMerger(
+ k.distroPath,
+ k.configPath,
+ "kfd-v1alpha2",
+ "onpremises",
+ )
+ if err != nil {
+ return fmt.Errorf("error creating furyctl merger: %w", err)
+ }
+
+ mCfg, err := template.NewConfigWithoutData(furyctlMerger, []string{})
+ if err != nil {
+ return fmt.Errorf("error creating template config: %w", err)
+ }
+
+ mCfg.Data["kubernetes"] = map[any]any{
+ "version": k.kfdManifest.Kubernetes.OnPremises.Version,
+ }
+
+ mCfg.Data["paths"] = map[any]any{
+ "helm": "",
+ "helmfile": "",
+ "kubectl": "",
+ "kustomize": "",
+ "terraform": "",
+ "vendorPath": "",
+ "yq": "",
+ }
+
+ mCfg.Data["options"] = map[any]any{
+ "skipPodsRunningCheck": false,
+ "podRunningTimeout": "",
+ }
+
+ if err := k.CopyFromTemplate(
+ mCfg,
+ "kubernetes",
+ path.Join(k.distroPath, "templates", cluster.OperationPhaseKubernetes, "onpremises"),
+ tmpDir,
+ k.configPath,
+ ); err != nil {
+ return fmt.Errorf("error copying from template: %w", err)
+ }
+
+ if _, err := ansibleRunner.Exec("all", "-m", "ping"); err != nil {
+ return fmt.Errorf("error checking hosts: %w", err)
+ }
+
+ if _, err := ansibleRunner.Playbook("98.cluster-certificates-renewal.yaml"); err != nil {
+ return fmt.Errorf("error renewing certificates: %w", err)
+ }
+
+ return nil
+}
diff --git a/internal/apis/kfd/v1alpha2/onpremises/create/distribution.go b/internal/apis/kfd/v1alpha2/onpremises/create/distribution.go
index 6a4faa56d..368957da3 100644
--- a/internal/apis/kfd/v1alpha2/onpremises/create/distribution.go
+++ b/internal/apis/kfd/v1alpha2/onpremises/create/distribution.go
@@ -289,6 +289,10 @@ func (d *Distribution) injectStoredConfig(cfg template.Config) (template.Config,
return cfg, nil
}
+func (d *Distribution) SetUpgrade(upgradeEnabled bool) {
+ d.upgrade.Enabled = upgradeEnabled
+}
+
func NewDistribution(
furyctlConf public.OnpremisesKfdV1Alpha2,
kfdManifest config.KFD,
diff --git a/internal/apis/kfd/v1alpha2/onpremises/create/kubernetes.go b/internal/apis/kfd/v1alpha2/onpremises/create/kubernetes.go
index 6315adf18..24278de78 100644
--- a/internal/apis/kfd/v1alpha2/onpremises/create/kubernetes.go
+++ b/internal/apis/kfd/v1alpha2/onpremises/create/kubernetes.go
@@ -212,6 +212,10 @@ func (k *Kubernetes) postKubernetes(
return nil
}
+func (k *Kubernetes) SetUpgrade(upgradeEnabled bool) {
+ k.upgrade.Enabled = upgradeEnabled
+}
+
func NewKubernetes(
furyctlConf public.OnpremisesKfdV1Alpha2,
kfdManifest config.KFD,
diff --git a/internal/apis/kfd/v1alpha2/onpremises/creator.go b/internal/apis/kfd/v1alpha2/onpremises/creator.go
index 92248245b..af075c314 100644
--- a/internal/apis/kfd/v1alpha2/onpremises/creator.go
+++ b/internal/apis/kfd/v1alpha2/onpremises/creator.go
@@ -52,6 +52,7 @@ type ClusterCreator struct {
upgrade bool
externalUpgradesPath string
upgradeNode string
+ postApplyPhases []string
}
func (c *ClusterCreator) SetProperties(props []cluster.CreatorProperty) {
@@ -140,6 +141,11 @@ func (c *ClusterCreator) SetProperty(name string, value any) {
if s, ok := value.(string); ok {
c.upgradeNode = s
}
+
+ case cluster.CreatorPropertyPostApplyPhases:
+ if s, ok := value.([]string); ok {
+ c.postApplyPhases = s
+ }
}
}
@@ -427,6 +433,61 @@ func (c *ClusterCreator) allPhases(
}
}
+ if len(c.postApplyPhases) > 0 {
+ logrus.Info("Executing extra phases...")
+
+ if err := c.extraPhases(
+ kubernetesPhase,
+ distributionPhase,
+ pluginsPhase,
+ upgr,
+ upgradeState,
+ ); err != nil {
+ return fmt.Errorf("error while executing extra phases: %w", err)
+ }
+ }
+
+ return nil
+}
+
+func (c *ClusterCreator) extraPhases(
+ kubernetesPhase upgrade.OperatorPhase,
+ distributionPhase upgrade.ReducersOperatorPhase[reducers.Reducers],
+ pluginsPhase *commcreate.Plugins,
+ upgr *upgrade.Upgrade,
+ upgradeState *upgrade.State,
+) error {
+ initialUpgrade := upgr.Enabled
+
+ defer func() {
+ upgr.Enabled = initialUpgrade
+ }()
+
+ for _, phase := range c.postApplyPhases {
+ switch phase {
+ case cluster.OperationPhaseKubernetes:
+ kubernetesPhase.SetUpgrade(false)
+
+ if err := kubernetesPhase.Exec(StartFromFlagNotSet, upgradeState); err != nil {
+ return fmt.Errorf("error while executing kubernetes phase: %w", err)
+ }
+
+ case cluster.OperationPhaseDistribution:
+ distributionPhase.SetUpgrade(false)
+
+ if err := distributionPhase.Exec(nil, StartFromFlagNotSet, upgradeState); err != nil {
+ return fmt.Errorf("error while executing distribution phase: %w", err)
+ }
+
+ case cluster.OperationPhasePlugins:
+ if distribution.HasFeature(c.kfdManifest, distribution.FeaturePlugins) {
+ if err := pluginsPhase.Exec(); err != nil {
+ return fmt.Errorf("error while executing plugins phase: %w", err)
+ }
+ }
+ }
+ }
+
return nil
}
diff --git a/internal/apis/kfd/v1alpha2/onpremises/init.go b/internal/apis/kfd/v1alpha2/onpremises/init.go
index 3e333d732..992ad26b7 100644
--- a/internal/apis/kfd/v1alpha2/onpremises/init.go
+++ b/internal/apis/kfd/v1alpha2/onpremises/init.go
@@ -28,4 +28,10 @@ func init() {
"OnPremises",
cluster.NewKubeconfigFactory[*KubeconfigGetter, public.OnpremisesKfdV1Alpha2](&KubeconfigGetter{}),
)
+
+ cluster.RegisterCertificatesRenewerFactory(
+ "kfd.sighup.io/v1alpha2",
+ "OnPremises",
+ cluster.NewCertificatesRenewerFactory[*CertificatesRenewer, public.OnpremisesKfdV1Alpha2](&CertificatesRenewer{}),
+ )
}
diff --git a/internal/apis/kfd/v1alpha2/onpremises/kubeconfig_getter.go b/internal/apis/kfd/v1alpha2/onpremises/kubeconfig_getter.go
index 481fd6de5..eda3a1246 100644
--- a/internal/apis/kfd/v1alpha2/onpremises/kubeconfig_getter.go
+++ b/internal/apis/kfd/v1alpha2/onpremises/kubeconfig_getter.go
@@ -5,7 +5,6 @@
package onpremises
import (
- "errors"
"fmt"
"os"
"path"
@@ -22,8 +21,6 @@ import (
"github.com/sighupio/furyctl/pkg/template"
)
-var ErrKubeconfigNotSet = errors.New("KUBECONFIG env variable is not set")
-
type KubeconfigGetter struct {
*cluster.OperationPhase
furyctlConf public.OnpremisesKfdV1Alpha2
diff --git a/internal/cluster/certificates_renewer.go b/internal/cluster/certificates_renewer.go
new file mode 100644
index 000000000..70ea5b5e7
--- /dev/null
+++ b/internal/cluster/certificates_renewer.go
@@ -0,0 +1,93 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//nolint:dupl // ignoring duplication linting error
+package cluster
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/sighupio/fury-distribution/pkg/apis/config"
+ yamlx "github.com/sighupio/furyctl/pkg/x/yaml"
+)
+
+const (
+ CertificatesRenewerPropertyOutdir = "outdir"
+ CertificatesRenewerPropertyFuryctlConf = "furyctlconf"
+ CertificatesRenewerPropertyConfigPath = "configpath"
+ CertificatesRenewerPropertyKfdManifest = "kfdmanifest"
+ CertificatesRenewerPropertyDistroPath = "distropath"
+)
+
+var certificatesRenewerFactories = make(map[string]map[string]CertificatesRenewerFactory) //nolint:gochecknoglobals, lll // This patterns requires certificatesRenewerFactories as global to work with init function.
+
+type CertificatesRenewerFactory func(configPath string, props []CertificatesRenewerProperty) (CertificatesRenewer, error) //nolint:lll // This pattern requires CertificatesRenewerFactory as global to work with init function.
+
+type CertificatesRenewerProperty struct {
+ Name string
+ Value any
+}
+
+type CertificatesRenewer interface {
+ SetProperties(props []CertificatesRenewerProperty)
+ SetProperty(name string, value any)
+ Renew() error
+}
+
+func NewCertificatesRenewer(
+ minimalConf config.Furyctl,
+ kfdManifest config.KFD,
+ distroPath string,
+ configPath string,
+ outDir string,
+) (CertificatesRenewer, error) {
+ lcAPIVersion := strings.ToLower(minimalConf.APIVersion)
+ lcResourceType := strings.ToLower(minimalConf.Kind)
+
+ if factoryFn, ok := certificatesRenewerFactories[lcAPIVersion][lcResourceType]; ok {
+ return factoryFn(configPath, []CertificatesRenewerProperty{
+ {
+ Name: CertificatesRenewerPropertyKfdManifest,
+ Value: kfdManifest,
+ },
+ {
+ Name: CertificatesRenewerPropertyOutdir,
+ Value: outDir,
+ },
+ {
+ Name: CertificatesRenewerPropertyDistroPath,
+ Value: distroPath,
+ },
+ })
+ }
+
+ return nil, fmt.Errorf("%w - type '%s' api version '%s'", errResourceNotSupported, lcResourceType, lcAPIVersion)
+}
+
+func RegisterCertificatesRenewerFactory(apiVersion, kind string, factory CertificatesRenewerFactory) {
+ lcAPIVersion := strings.ToLower(apiVersion)
+ lcKind := strings.ToLower(kind)
+
+ if _, ok := certificatesRenewerFactories[lcAPIVersion]; !ok {
+ certificatesRenewerFactories[lcAPIVersion] = make(map[string]CertificatesRenewerFactory)
+ }
+
+ certificatesRenewerFactories[lcAPIVersion][lcKind] = factory
+}
+
+func NewCertificatesRenewerFactory[T CertificatesRenewer, S any](cc T) CertificatesRenewerFactory {
+ return func(configPath string, props []CertificatesRenewerProperty) (CertificatesRenewer, error) {
+ furyctlConf, err := yamlx.FromFileV3[S](configPath)
+ if err != nil {
+ return nil, err
+ }
+
+ cc.SetProperty(CertificatesRenewerPropertyConfigPath, configPath)
+ cc.SetProperty(CertificatesRenewerPropertyFuryctlConf, furyctlConf)
+ cc.SetProperties(props)
+
+ return cc, nil
+ }
+}
diff --git a/internal/cluster/creator.go b/internal/cluster/creator.go
index ccf99ea19..d2989cbfc 100644
--- a/internal/cluster/creator.go
+++ b/internal/cluster/creator.go
@@ -29,6 +29,7 @@ const (
CreatorPropertyUpgrade = "upgrade"
CreatorPropertyExternalUpgradesPath = "externalupgradespath"
CreatorPropertyUpgradeNode = "upgradenode"
+ CreatorPropertyPostApplyPhases = "postapplyphases"
)
var (
@@ -72,6 +73,7 @@ func NewCreator(
upgrade bool,
externalUpgradesPath,
upgradeNode string,
+ postApplyPhases []string,
) (Creator, error) {
lcAPIVersion := strings.ToLower(minimalConf.APIVersion)
lcResourceType := strings.ToLower(minimalConf.Kind)
@@ -130,6 +132,10 @@ func NewCreator(
Name: CreatorPropertyUpgradeNode,
Value: upgradeNode,
},
+ {
+ Name: CreatorPropertyPostApplyPhases,
+ Value: postApplyPhases,
+ },
})
}
diff --git a/internal/cluster/kubeconfig_getter.go b/internal/cluster/kubeconfig_getter.go
index b86984a07..06457b3bb 100644
--- a/internal/cluster/kubeconfig_getter.go
+++ b/internal/cluster/kubeconfig_getter.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//nolint:dupl // ignoring duplication linting error
package cluster
import (
diff --git a/internal/cluster/phase.go b/internal/cluster/phase.go
index 3167b2adb..fed54422d 100644
--- a/internal/cluster/phase.go
+++ b/internal/cluster/phase.go
@@ -88,6 +88,19 @@ func ValidateOperationPhase(phase string) error {
}
}
+func ValidateMainPhases(phase string) error {
+ switch phase {
+ case OperationPhaseInfrastructure,
+ OperationPhaseKubernetes,
+ OperationPhaseDistribution,
+ OperationPhasePlugins:
+ return nil
+
+ default:
+ return ErrUnsupportedPhase
+ }
+}
+
func GetPhasesOrder() []string {
return []string{
"PreInfrastructure",
diff --git a/internal/clusterpki/clusterpki.go b/internal/clusterpki/clusterpki.go
new file mode 100644
index 000000000..42bdd8eda
--- /dev/null
+++ b/internal/clusterpki/clusterpki.go
@@ -0,0 +1,85 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package clusterpki
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/sirupsen/logrus"
+ pki "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
+)
+
+type ClusterPKI struct {
+ Config
+}
+
+// Config represents the configuration for the whole cluster's PKI.
+type Config struct {
+ Etcd EtcdConfig `json:"etcd"`
+ ControlPlane ControlPlaneConfig `json:"controlPlane"`
+ Path string `json:"path"`
+ CertConfig pki.CertConfig `json:"certConfig"`
+}
+
+// EtcdConfig is used to store the path to the several certificates for etcd.
+type EtcdConfig struct {
+ CertDir string `json:"certDir"`
+ CaCertFilename string `json:"caCertFilename"`
+ CaKeyFilename string `json:"caKeyFilename"`
+ ClientCertFilename string `json:"clientCertFilename"`
+ ClientKeyFilename string `json:"clientKeyFilename"`
+}
+
+// ControlPlaneConfig is used to store the path to the several certificates for the control plane.
+type ControlPlaneConfig struct {
+ CertDir string `json:"certDir"`
+ CaCertFile string `json:"caCertFilename"`
+ CaKeyFile string `json:"caKeyFilename"`
+ SaPubFile string `json:"saPubFilename"`
+ SaKeyFile string `json:"saKeyFilename"`
+ ProxyCaCertFile string `json:"proxyCaCertFilename"`
+ ProxyKeyCertFile string `json:"proxyKeyCertFilename"`
+}
+
+func (c *Config) save(files map[string][]byte, dir string) error {
+ const (
+ permOwnerGroup os.FileMode = 0o770
+ )
+
+ basePath := filepath.Join(c.Path, dir)
+ logrus.Debugf("checking if target path %s exists before proceeding", basePath)
+
+ _, err := os.Stat(basePath)
+ if err == nil {
+ logrus.Errorf("path '%s' already exists. Delete the folder first if you want to replace its content", basePath)
+
+ return os.ErrExist
+ } else if errors.Is(err, os.ErrNotExist) {
+ for filename, file := range files {
+ fullPath := filepath.Join(basePath, filename)
+
+ logrus.Debug("processing file ", fullPath)
+
+ if err := os.MkdirAll(basePath, permOwnerGroup); err != nil {
+ return fmt.Errorf("got an error trying to create dirs %s: %w", basePath, err)
+ }
+
+ if err := os.WriteFile(fullPath, file, permOwnerGroup); err != nil {
+ return fmt.Errorf("error while saving file %s: %w", fullPath, err)
+ }
+
+ logrus.Debug("file successfully saved:", fullPath)
+ }
+
+ logrus.Debug("all files saved successfully")
+
+ return nil
+ }
+
+ return fmt.Errorf("unexpected error while checking if path exists: %w", err)
+}
diff --git a/internal/clusterpki/controlplane.go b/internal/clusterpki/controlplane.go
new file mode 100644
index 000000000..44e913d4e
--- /dev/null
+++ b/internal/clusterpki/controlplane.go
@@ -0,0 +1,58 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package clusterpki
+
+import (
+ "github.com/sirupsen/logrus"
+ pki "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
+)
+
+const (
+ ControlPlaneSaKey = "sa.key"
+ ControlPlaneSaPub = "sa.pub"
+ ControlPlaneFProxyCrt = "front-proxy-ca.crt"
+ ControlPlaneFProxyKey = "front-proxy-ca.key"
+ ControlPlaneCaKey = "ca.key"
+ ControlPlaneCaCrt = "ca.crt"
+ ControlPlanePath = "master"
+ // We default to `master` as the folder name instead of controlplane because
+ // that is where KFD's playbook template expects it.
+ // See file fury-distribution/templates/kubernetes/onpremises/create-playbook.yaml.tpl at line 23.
+
+)
+
+// ControlPlanePKI implements the ClusterComponent interface.
+type ControlPlanePKI struct {
+ ClusterPKI
+}
+
+func (cp ControlPlanePKI) Create() error {
+ // Create certificates for Kubernetes control plane.
+ caCert, caKey, err := pki.NewCertificateAuthority(&cp.CertConfig)
+ if err != nil {
+ logrus.Fatal(err)
+ }
+
+ saCert, saKey, err := pki.NewCertificateAuthority(&cp.CertConfig)
+ if err != nil {
+ logrus.Fatal(err)
+ }
+
+ fpCert, fpKey, err := pki.NewCertificateAuthority(&cp.CertConfig)
+ if err != nil {
+ logrus.Fatal(err)
+ }
+
+ certs := map[string][]byte{
+ ControlPlaneCaCrt: pki.EncodeCertPEM(caCert),
+ ControlPlaneCaKey: EncodePrivateKey(caKey),
+ ControlPlaneSaPub: pki.EncodeCertPEM(saCert),
+ ControlPlaneSaKey: EncodePrivateKey(saKey),
+ ControlPlaneFProxyCrt: pki.EncodeCertPEM(fpCert),
+ ControlPlaneFProxyKey: EncodePrivateKey(fpKey),
+ }
+
+ return cp.save(certs, ControlPlanePath)
+}
diff --git a/internal/clusterpki/etcd.go b/internal/clusterpki/etcd.go
new file mode 100644
index 000000000..cd9c4aa37
--- /dev/null
+++ b/internal/clusterpki/etcd.go
@@ -0,0 +1,36 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package clusterpki
+
+import (
+ "fmt"
+
+ pki "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
+)
+
+const (
+ EtcdCaCrt = "ca.crt"
+ EtcdCaKey = "ca.key"
+ etcdPath = "etcd"
+)
+
+// Etcd implements the ClusterComponent Interface.
+type Etcd struct {
+ ClusterPKI
+}
+
+func (e Etcd) Create() error {
+ ca, privateKey, err := pki.NewCertificateAuthority(&e.CertConfig)
+ if err != nil {
+ return fmt.Errorf("error while creating CA for etcd: %w", err)
+ }
+
+ certs := map[string][]byte{
+ EtcdCaCrt: pki.EncodeCertPEM(ca),
+ EtcdCaKey: EncodePrivateKey(privateKey),
+ }
+
+ return e.save(certs, etcdPath)
+}
diff --git a/internal/clusterpki/key.go b/internal/clusterpki/key.go
new file mode 100644
index 000000000..c71c7ea4d
--- /dev/null
+++ b/internal/clusterpki/key.go
@@ -0,0 +1,22 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package clusterpki
+
+import (
+ "crypto"
+
+ "github.com/sirupsen/logrus"
+ "k8s.io/client-go/util/keyutil"
+)
+
+func EncodePrivateKey(key crypto.PrivateKey) []byte {
+ mKey, err := keyutil.MarshalPrivateKeyToPEM(key)
+ if err != nil {
+ // This is an unmanaged error, we should os.Exit() here but the linter does not let us.
+ logrus.Error("error while encoding private key: ", err)
+ }
+
+ return mKey
+}
diff --git a/internal/distribution/compatibility.go b/internal/distribution/compatibility.go
index 407a72ec2..31f6e110a 100644
--- a/internal/distribution/compatibility.go
+++ b/internal/distribution/compatibility.go
@@ -85,7 +85,7 @@ func (c *EKSClusterCheck) IsCompatible() bool {
return false
}
- max12SevenVersion, err := semver.NewVersion("v1.27.6")
+ max12SevenVersion, err := semver.NewVersion("v1.27.7")
if err != nil {
return false
}
@@ -95,7 +95,7 @@ func (c *EKSClusterCheck) IsCompatible() bool {
return false
}
- max12EightVersion, err := semver.NewVersion("v1.28.1")
+ max12EightVersion, err := semver.NewVersion("v1.28.2")
if err != nil {
return false
}
@@ -105,7 +105,7 @@ func (c *EKSClusterCheck) IsCompatible() bool {
return false
}
- max12NineVersion, err := semver.NewVersion("v1.29.1")
+ max12NineVersion, err := semver.NewVersion("v1.29.2")
if err != nil {
return false
}
@@ -158,7 +158,7 @@ func (c *KFDDistributionCheck) IsCompatible() bool {
return false
}
- max12SevenVersion, err := semver.NewVersion("v1.27.6")
+ max12SevenVersion, err := semver.NewVersion("v1.27.7")
if err != nil {
return false
}
@@ -168,7 +168,7 @@ func (c *KFDDistributionCheck) IsCompatible() bool {
return false
}
- max12EightVersion, err := semver.NewVersion("v1.28.1")
+ max12EightVersion, err := semver.NewVersion("v1.28.2")
if err != nil {
return false
}
@@ -178,7 +178,7 @@ func (c *KFDDistributionCheck) IsCompatible() bool {
return false
}
- max12NineVersion, err := semver.NewVersion("v1.29.1")
+ max12NineVersion, err := semver.NewVersion("v1.29.2")
if err != nil {
return false
}
@@ -231,7 +231,7 @@ func (c *OnPremisesCheck) IsCompatible() bool {
return false
}
- max12SevenVersion, err := semver.NewVersion("v1.27.6")
+ max12SevenVersion, err := semver.NewVersion("v1.27.7")
if err != nil {
return false
}
@@ -241,7 +241,7 @@ func (c *OnPremisesCheck) IsCompatible() bool {
return false
}
- max12EightVersion, err := semver.NewVersion("v1.28.1")
+ max12EightVersion, err := semver.NewVersion("v1.28.2")
if err != nil {
return false
}
@@ -251,7 +251,7 @@ func (c *OnPremisesCheck) IsCompatible() bool {
return false
}
- max12NineVersion, err := semver.NewVersion("v1.29.1")
+ max12NineVersion, err := semver.NewVersion("v1.29.2")
if err != nil {
return false
}
diff --git a/internal/distribution/compatibility_test.go b/internal/distribution/compatibility_test.go
index 34c405a2b..b9b975bdd 100644
--- a/internal/distribution/compatibility_test.go
+++ b/internal/distribution/compatibility_test.go
@@ -51,20 +51,30 @@ func TestEKSClusterCheckIsCompatible(t *testing.T) {
expected: false,
},
{
- name: "should return false if distribution version is greater than 1.27.6",
- distributionVersion: "v1.27.7",
+ name: "should return false if distribution version is greater than 1.27.7",
+ distributionVersion: "v1.27.8",
expected: false,
},
{
- name: "should return true if distribution version is equal to 1.28.1",
- distributionVersion: "v1.28.1",
+ name: "should return true if distribution version is greater than 1.28.0 and less than 1.28.3",
+ distributionVersion: "v1.28.2",
expected: true,
},
{
- name: "should return true if distribution version is equal to 1.29.1",
- distributionVersion: "v1.29.1",
+ name: "should return false if distribution version is greater than 1.28.2",
+ distributionVersion: "v1.28.3",
+ expected: false,
+ },
+ {
+ name: "should return true if distribution version is greater than 1.29.0 and less than 1.29.3",
+ distributionVersion: "v1.29.2",
expected: true,
},
+ {
+ name: "should return false if distribution version is greater than 1.29.2",
+ distributionVersion: "v1.29.3",
+ expected: false,
+ },
}
for _, tc := range testCases {
@@ -128,20 +138,30 @@ func TestKFDDistributionCheckIsCompatible(t *testing.T) {
expected: true,
},
{
- name: "should return false if distribution version is greater than 1.27.6",
- distributionVersion: "v1.27.7",
+ name: "should return false if distribution version is greater than 1.27.7",
+ distributionVersion: "v1.27.8",
expected: false,
},
{
- name: "should return true if distribution version is equal to 1.28.1",
- distributionVersion: "v1.28.1",
+ name: "should return true if distribution version is greater than 1.28.0 and less than 1.28.3",
+ distributionVersion: "v1.28.2",
expected: true,
},
{
- name: "should return true if distribution version is equal to 1.29.1",
- distributionVersion: "v1.29.1",
+ name: "should return false if distribution version is greater than 1.28.2",
+ distributionVersion: "v1.28.3",
+ expected: false,
+ },
+ {
+ name: "should return true if distribution version is greater than 1.29.0 and less than 1.29.3",
+ distributionVersion: "v1.29.2",
expected: true,
},
+ {
+ name: "should return false if distribution version is greater than 1.29.2",
+ distributionVersion: "v1.29.3",
+ expected: false,
+ },
}
for _, tc := range testCases {
@@ -205,20 +225,30 @@ func TestOnPremisesCheckIsCompatible(t *testing.T) {
expected: true,
},
{
- name: "should return false if distribution version is greater than 1.27.6",
- distributionVersion: "v1.27.7",
+ name: "should return false if distribution version is greater than 1.27.7",
+ distributionVersion: "v1.27.8",
expected: false,
},
{
- name: "should return true if distribution version is equal to 1.28.1",
- distributionVersion: "v1.28.1",
+ name: "should return true if distribution version is greater than 1.28.0 and less than 1.28.3",
+ distributionVersion: "v1.28.2",
expected: true,
},
{
- name: "should return true if distribution version is equal to 1.29.1",
- distributionVersion: "v1.29.1",
+ name: "should return false if distribution version is greater than 1.28.2",
+ distributionVersion: "v1.28.3",
+ expected: false,
+ },
+ {
+ name: "should return true if distribution version is greater than 1.29.0 and less than 1.29.3",
+ distributionVersion: "v1.29.2",
expected: true,
},
+ {
+ name: "should return false if distribution version is greater than 1.29.2",
+ distributionVersion: "v1.29.3",
+ expected: false,
+ },
}
for _, tc := range testCases {
diff --git a/internal/lockfile/lockfile.go b/internal/lockfile/lockfile.go
new file mode 100644
index 000000000..9d78ff103
--- /dev/null
+++ b/internal/lockfile/lockfile.go
@@ -0,0 +1,59 @@
+// Copyright (c) 2017-present SIGHUP s.r.l All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package lockfile
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+)
+
+var ErrLockFileExists = errors.New(
+ "lock file exists. This usually means that there is another instance of furyctl running",
+)
+
+type LockFile struct {
+ Path string
+}
+
+func NewLockFile(clusterName string) *LockFile {
+ fileName := "furyctl-" + clusterName
+
+ path := filepath.Join(os.TempDir(), fileName)
+
+ return &LockFile{Path: path}
+}
+
+func (l *LockFile) Verify() error {
+ _, err := os.Stat(l.Path)
+ if err == nil {
+ return ErrLockFileExists
+ }
+
+ if !os.IsNotExist(err) {
+ return fmt.Errorf("error while checking lock file: %w", err)
+ }
+
+ return nil
+}
+
+func (l *LockFile) Create() error {
+ _, err := os.Create(l.Path)
+ if err != nil {
+ return fmt.Errorf("error while creating lock file: %w", err)
+ }
+
+ return nil
+}
+
+func (l *LockFile) Remove() error {
+ err := os.Remove(l.Path)
+ if err != nil {
+ return fmt.Errorf("error while removing lock file: %w", err)
+ }
+
+ return nil
+}
diff --git a/internal/parser/config.go b/internal/parser/config.go
index 782823a36..77f76c8cd 100644
--- a/internal/parser/config.go
+++ b/internal/parser/config.go
@@ -52,7 +52,10 @@ func (p *ConfigParser) ParseDynamicValue(val any) (string, error) {
return filepath.Join(p.baseDir, filepath.Clean(sourceValue)), nil
case Env:
- envVar := os.Getenv(sourceValue)
+ envVar, exists := os.LookupEnv(sourceValue)
+ if !exists {
+ return "", fmt.Errorf("%w: %s is empty", ErrCannotParseDynamicValue, sourceValue)
+ }
envVar = strings.TrimRight(envVar, "\n")
diff --git a/internal/upgrade/storedecorator.go b/internal/upgrade/storedecorator.go
index b91b250ad..c51e02637 100644
--- a/internal/upgrade/storedecorator.go
+++ b/internal/upgrade/storedecorator.go
@@ -14,6 +14,7 @@ type (
Reducers = any
ReducersOperatorPhase[T Reducers] interface {
Exec(reducers T, startFrom string, upgradeState *State) error
+ SetUpgrade(upgradeEnabled bool)
Self() *cluster.OperationPhase
}
)
@@ -66,6 +67,10 @@ func (d *ReducerOperatorPhaseDecorator[T]) Exec(reducers T, startFrom string, up
return nil
}
+func (d *ReducerOperatorPhaseDecorator[T]) SetUpgrade(upgradeEnabled bool) {
+ d.upgr.Enabled = upgradeEnabled
+}
+
func (d *ReducerOperatorPhaseDecorator[T]) Self() *cluster.OperationPhase {
return d.phase.Self()
}
@@ -113,6 +118,10 @@ func (d *ReducerOperatorPhaseAsyncDecorator[T]) Exec(reducers T, startFrom strin
return nil
}
+func (d *ReducerOperatorPhaseAsyncDecorator[T]) SetUpgrade(upgradeEnabled bool) { //nolint: lll,revive // confusing-naming is a false positive
+ d.upgr.Enabled = upgradeEnabled
+}
+
func (d *ReducerOperatorPhaseAsyncDecorator[T]) Stop() error {
if err := d.phase.Stop(); err != nil {
return fmt.Errorf("error while stopping phase: %w", err)
@@ -128,6 +137,7 @@ func (d *ReducerOperatorPhaseAsyncDecorator[T]) Self() *cluster.OperationPhase {
type OperatorPhase interface {
Exec(startFrom string, upgradeState *State) error
Self() *cluster.OperationPhase
+ SetUpgrade(upgradeEnabled bool)
}
type OperatorPhaseAsync interface {
@@ -178,6 +188,10 @@ func (d *OperatorPhaseDecorator) Exec(startFrom string, upgradeState *State) err
return nil
}
+func (d *OperatorPhaseDecorator) SetUpgrade(upgradeEnabled bool) {
+ d.upgr.Enabled = upgradeEnabled
+}
+
func (d *OperatorPhaseDecorator) Self() *cluster.OperationPhase {
return d.phase.Self()
}
@@ -233,6 +247,10 @@ func (d *OperatorPhaseAsyncDecorator) Stop() error {
return nil
}
+func (d *OperatorPhaseAsyncDecorator) SetUpgrade(upgradeEnabled bool) {
+ d.upgr.Enabled = upgradeEnabled
+}
+
func (d *OperatorPhaseAsyncDecorator) Self() *cluster.OperationPhase {
return d.phase.Self()
}