Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: add support for namespace other than flux-system #3532

Closed
wants to merge 7 commits into from
9 changes: 8 additions & 1 deletion cmd/gitops/app/bootstrap/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

const (
wgeDefaultNamespace = "flux-system"
cmdName = "bootstrap"
cmdShortDescription = "Installs Weave GitOps Enterprise in simple steps"
cmdLongDescription = `Installs Weave GitOps Enterprise in simple steps:
Expand All @@ -29,10 +30,15 @@ gitops bootstrap --kubeconfig <your-kubeconfig-location>

# Start WGE installation with given 'username' and 'password'
gitops bootstrap --username wego-admin --password=hell0!

# Start WGE installation within different namespace than flux-system
gitops bootstrap -n test-namespace

`
)

type bootstrapFlags struct {
namespace string
username string
password string
version string
Expand All @@ -52,7 +58,7 @@ func Command(opts *config.Options) *cobra.Command {
Example: cmdExamples,
RunE: getBootstrapCmdRun(opts),
}

cmd.PersistentFlags().StringVarP(&flags.namespace, "namespace", "n", wgeDefaultNamespace, "The namespace scope for this operation")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this flag different to

rootCmd.PersistentFlags().StringP("namespace", "n", defaultNamespace, "The namespace scope for this operation")
?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm overriding it to be able to pass it to the commands
The root app doesn't refer it to a pointer or variable

cmd.Flags().StringVarP(&flags.username, "username", "u", "", "dashboard admin username")
cmd.Flags().StringVarP(&flags.password, "password", "p", "", "dashboard admin password")
cmd.Flags().StringVarP(&flags.version, "version", "v", "", "version of Weave GitOps Enterprise (should be from the latest 3 versions)")
Expand All @@ -72,6 +78,7 @@ func getBootstrapCmdRun(opts *config.Options) func(*cobra.Command, []string) err
c, err := steps.NewConfigBuilder().
WithLogWriter(cliLogger).
WithKubeconfig(opts.Kubeconfig).
WithNamespace(flags.namespace).
WithUsername(flags.username).
WithPassword(flags.password).
WithVersion(flags.version).
Expand Down
8 changes: 4 additions & 4 deletions pkg/bootstrap/steps/admin_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func NewAskAdminCredsSecretStep(config Config) BootstrapStep {
Msg: existingCredsMsg,
DefaultValue: "",
Valuesfn: isExistingAdminSecret,
StepInformation: fmt.Sprintf(adminSecretExistsMsgFormat, adminSecretName, WGEDefaultNamespace),
StepInformation: fmt.Sprintf(adminSecretExistsMsgFormat, adminSecretName, config.Namespace),
},
}

Expand Down Expand Up @@ -99,7 +99,7 @@ func createCredentials(input []StepInput, c *Config) ([]StepOutput, error) {

if existing, _ := isExistingAdminSecret(input, c); existing.(bool) {
if continueWithExistingCreds != confirmYes {
return []StepOutput{}, fmt.Errorf(existingCredsExitMsg, adminSecretName, WGEDefaultNamespace)
return []StepOutput{}, fmt.Errorf(existingCredsExitMsg, adminSecretName, c.Namespace)
} else {
return []StepOutput{}, nil
}
Expand All @@ -119,7 +119,7 @@ func createCredentials(input []StepInput, c *Config) ([]StepOutput, error) {
secret := corev1.Secret{
ObjectMeta: v1.ObjectMeta{
Name: adminSecretName,
Namespace: WGEDefaultNamespace,
Namespace: c.Namespace,
},
Data: data,
}
Expand All @@ -139,7 +139,7 @@ func createCredentials(input []StepInput, c *Config) ([]StepOutput, error) {
// returns true if admin secret is already on the cluster
// returns false if no admin secret on the cluster
func isExistingAdminSecret(input []StepInput, c *Config) (interface{}, error) {
_, err := utils.GetSecret(c.KubernetesClient, adminSecretName, WGEDefaultNamespace)
_, err := utils.GetSecret(c.KubernetesClient, adminSecretName, c.Namespace)
if err != nil {
return false, nil
}
Expand Down
12 changes: 7 additions & 5 deletions pkg/bootstrap/steps/admin_password_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestCreateCredentials(t *testing.T) {
Value: v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: adminSecretName,
Namespace: WGEDefaultNamespace,
Namespace: testNamespace,
},
Data: map[string][]byte{
"username": []byte("wego-admin"),
Expand All @@ -56,7 +56,7 @@ func TestCreateCredentials(t *testing.T) {
{
name: "secret exist and user refuse to continue",
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: adminSecretName, Namespace: WGEDefaultNamespace},
ObjectMeta: metav1.ObjectMeta{Name: adminSecretName, Namespace: testNamespace},
Type: "Opaque",
Data: map[string][]byte{
"username": []byte("test-username"),
Expand All @@ -83,7 +83,7 @@ func TestCreateCredentials(t *testing.T) {
{
name: "secret exist and user continue",
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: adminSecretName, Namespace: WGEDefaultNamespace},
ObjectMeta: metav1.ObjectMeta{Name: adminSecretName, Namespace: testNamespace},
Type: "Opaque",
Data: map[string][]byte{
"username": []byte("test-username"),
Expand Down Expand Up @@ -112,7 +112,7 @@ func TestCreateCredentials(t *testing.T) {
Value: v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: adminSecretName,
Namespace: WGEDefaultNamespace,
Namespace: testNamespace,
},
Data: map[string][]byte{
"username": []byte("wego-admin"),
Expand All @@ -126,7 +126,9 @@ func TestCreateCredentials(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := makeTestConfig(t, Config{}, tt.secret)
config := makeTestConfig(t, Config{
Namespace: testNamespace,
}, tt.secret)

out, err := createCredentials(tt.input, &config)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions pkg/bootstrap/steps/common_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import (
"k8s.io/apimachinery/pkg/runtime"
)

const testNamespace = "test-ns"

func makeTestConfig(t *testing.T, config Config, objects ...runtime.Object) Config {
fakeClient := utils.CreateFakeClient(t, objects...)
cliLogger := utils.CreateLogger()
return Config{
KubernetesClient: fakeClient,
Logger: cliLogger,
Namespace: config.Namespace,
WGEVersion: config.WGEVersion,
DomainType: config.DomainType,
Username: config.UserDomain,
Expand Down
9 changes: 9 additions & 0 deletions pkg/bootstrap/steps/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const (
type ConfigBuilder struct {
logger logger.Logger
kubeconfig string
namespace string
username string
password string
wGEVersion string
Expand All @@ -59,6 +60,11 @@ func (c *ConfigBuilder) WithLogWriter(logger logger.Logger) *ConfigBuilder {
return c
}

func (c *ConfigBuilder) WithNamespace(namespace string) *ConfigBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is flux-system resolved if no namespace is set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the flag itself, if it's not passed, then automatically set to flux system

c.namespace = namespace
return c
}

func (c *ConfigBuilder) WithUsername(username string) *ConfigBuilder {
c.username = username
return c
Expand Down Expand Up @@ -103,6 +109,8 @@ type Config struct {
KubernetesClient k8s_client.Client
Logger logger.Logger

Namespace string

WGEVersion string // user want this version in the cluster

Username string // cluster user username
Expand Down Expand Up @@ -142,6 +150,7 @@ func (cb *ConfigBuilder) Build() (Config, error) {
return Config{
KubernetesClient: kubeHttp.Client,
WGEVersion: cb.wGEVersion,
Namespace: cb.namespace,
Username: cb.username,
Password: cb.password,
Logger: cb.logger,
Expand Down
2 changes: 1 addition & 1 deletion pkg/bootstrap/steps/domain_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestSelectDomainType(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := makeTestConfig(t, Config{})
config := makeTestConfig(t, Config{Namespace: testNamespace})

_, err := selectDomainType(tt.input, &config)
if err != nil {
Expand Down
10 changes: 5 additions & 5 deletions pkg/bootstrap/steps/entitlement.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const (
nonExistingEntitlementSecretMsg = "entitlement file is not found, To get Weave GitOps Entitelment secret, please contact *[email protected]* and add it to your cluster"
invalidEntitlementSecretMsg = "entitlement file is invalid, please verify the secret content. If you still facing issues, please contact *[email protected]*"
expiredEntitlementSecretMsg = "entitlement file is expired at: %s, please contact *[email protected]*"
entitlementCheckMsg = "verifying Weave GitOps Entitlement File"
entitlementCheckMsg = "verifying Weave GitOps Entitlement File in namespace: %s"
)

// wge consts
Expand All @@ -37,8 +37,8 @@ var CheckEntitlementSecret = BootstrapStep{
}

func checkEntitlementSecret(input []StepInput, c *Config) ([]StepOutput, error) {
c.Logger.Actionf(entitlementCheckMsg)
err := verifyEntitlementSecret(c.KubernetesClient)
c.Logger.Actionf(entitlementCheckMsg, c.Namespace)
err := verifyEntitlementSecret(c.KubernetesClient, c.Namespace)
if err != nil {
return []StepOutput{}, err
}
Expand All @@ -51,8 +51,8 @@ func checkEntitlementSecret(input []StepInput, c *Config) ([]StepOutput, error)
// verifing entitlement by the public key (private key is used for encrypting and public is for verification)
// and making sure it's not expired
// verifying username and password by making http request for downloading charts and ensuring it's authenticated
func verifyEntitlementSecret(client k8s_client.Client) error {
secret, err := utils.GetSecret(client, entitlementSecretName, WGEDefaultNamespace)
func verifyEntitlementSecret(client k8s_client.Client, namespace string) error {
secret, err := utils.GetSecret(client, entitlementSecretName, namespace)
if err != nil {
return fmt.Errorf("%s: %v", nonExistingEntitlementSecretMsg, err)
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/bootstrap/steps/entitlement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestCheckEntitlementFile(t *testing.T) {
{
name: "invalid entitlement",
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: entitlementSecretName, Namespace: WGEDefaultNamespace},
ObjectMeta: metav1.ObjectMeta{Name: entitlementSecretName, Namespace: testNamespace},
Type: "Opaque",
Data: map[string][]byte{
"entitlement": []byte(invalidEntitlement),
Expand All @@ -40,7 +40,7 @@ func TestCheckEntitlementFile(t *testing.T) {
{
name: "expired entitlement",
secret: &v1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: entitlementSecretName, Namespace: WGEDefaultNamespace},
ObjectMeta: metav1.ObjectMeta{Name: entitlementSecretName, Namespace: testNamespace},
Type: "Opaque",
Data: map[string][]byte{
"entitlement": []byte(expiredEntitlement),
Expand All @@ -54,7 +54,7 @@ func TestCheckEntitlementFile(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := makeTestConfig(t, Config{}, tt.secret)
config := makeTestConfig(t, Config{Namespace: testNamespace}, tt.secret)
_, err := checkEntitlementSecret([]StepInput{}, &config)
if err != nil {
if tt.err {
Expand Down
14 changes: 8 additions & 6 deletions pkg/bootstrap/steps/flux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package steps
import (
"fmt"

"github.com/weaveworks/weave-gitops-enterprise/pkg/bootstrap/utils"
"github.com/weaveworks/weave-gitops/pkg/runner"
)

Expand All @@ -11,7 +12,7 @@ const (
fluxBoostrapCheckMsg = "checking flux"
fluxExistingInstallMsg = "flux is installed"
fluxExistingBootstrapMsg = "flux is bootstrapped"
fluxRecoverMsg = "please bootstrap Flux in 'flux-system' namespace: more info https://fluxcd.io/flux/installation"
fluxRecoverMsg = "please bootstrap Flux: more info https://fluxcd.io/flux/installation"
)

// VerifyFluxInstallation checks that Flux is present in the cluster. It fails in case not and returns next steps to install it.
Expand All @@ -24,18 +25,19 @@ var VerifyFluxInstallation = BootstrapStep{
func verifyFluxInstallation(input []StepInput, c *Config) ([]StepOutput, error) {
var runner runner.CLIRunner

c.Logger.Actionf("verifying flux installation")
out, err := runner.Run("flux", "check")
c.Logger.Actionf("verifying flux installation in namespace: %s", c.Namespace)
out, err := runner.Run("flux", "check", "-n", c.Namespace)
if err != nil {
return []StepOutput{}, fmt.Errorf("flux installed error: %v. %s", string(out), fluxRecoverMsg)
}
c.Logger.Successf(fluxExistingInstallMsg)

c.Logger.Actionf("verifying flux reconcillation")
out, err = runner.Run("flux", "reconcile", "kustomization", "flux-system")
c.Logger.Actionf("verifying flux reconcillation in namespace: %s", c.Namespace)
err = utils.ReconcileFlux(c.Namespace)
if err != nil {
return []StepOutput{}, fmt.Errorf("flux bootstrapped error: %v. %s", string(out), fluxRecoverMsg)
return []StepOutput{}, fmt.Errorf("flux bootstrapped error: %v. %s", err, fluxRecoverMsg)
}

c.Logger.Successf(fluxExistingBootstrapMsg)

return []StepOutput{}, nil
Expand Down
15 changes: 7 additions & 8 deletions pkg/bootstrap/steps/install_wge.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const (
wgeChartName = "mccp"
wgeHelmRepositoryName = "weave-gitops-enterprise-charts"
WgeHelmReleaseName = "weave-gitops-enterprise"
WGEDefaultNamespace = "flux-system"
WGEDefaultRepoName = "flux-system"
wgeHelmrepoFileName = "wge-hrepo.yaml"
wgeHelmReleaseFileName = "wge-hrelease.yaml"
Expand Down Expand Up @@ -85,7 +84,7 @@ func installWge(input []StepInput, c *Config) ([]StepOutput, error) {

c.Logger.Actionf(wgeInstallMsg, c.WGEVersion)

wgehelmRepo, err := constructWgeHelmRepository()
wgehelmRepo, err := constructWgeHelmRepository(c.Namespace)
if err != nil {
return []StepOutput{}, err
}
Expand Down Expand Up @@ -127,7 +126,7 @@ func installWge(input []StepInput, c *Config) ([]StepOutput, error) {
ClusterController: clusterController,
}

wgeHelmRelease, err := constructWGEhelmRelease(values, c.WGEVersion)
wgeHelmRelease, err := constructWGEhelmRelease(c.Namespace, values, c.WGEVersion)
if err != nil {
return []StepOutput{}, err
}
Expand Down Expand Up @@ -158,11 +157,11 @@ func installWge(input []StepInput, c *Config) ([]StepOutput, error) {
}, nil
}

func constructWgeHelmRepository() (string, error) {
func constructWgeHelmRepository(namespace string) (string, error) {
wgeHelmRepo := sourcev1beta2.HelmRepository{
ObjectMeta: v1.ObjectMeta{
Name: wgeHelmRepositoryName,
Namespace: WGEDefaultNamespace,
Namespace: namespace,
},
Spec: sourcev1beta2.HelmRepositorySpec{
URL: wgeChartUrl,
Expand Down Expand Up @@ -201,7 +200,7 @@ func constructIngressValues(userDomain string) map[string]interface{} {
return ingressValues
}

func constructWGEhelmRelease(valuesFile valuesFile, chartVersion string) (string, error) {
func constructWGEhelmRelease(namespace string, valuesFile valuesFile, chartVersion string) (string, error) {
valuesBytes, err := json.Marshal(valuesFile)
if err != nil {
return "", err
Expand All @@ -210,15 +209,15 @@ func constructWGEhelmRelease(valuesFile valuesFile, chartVersion string) (string
wgeHelmRelease := helmv2.HelmRelease{
ObjectMeta: v1.ObjectMeta{
Name: WgeHelmReleaseName,
Namespace: WGEDefaultNamespace,
Namespace: namespace,
}, Spec: helmv2.HelmReleaseSpec{
Chart: helmv2.HelmChartTemplate{
Spec: helmv2.HelmChartTemplateSpec{
Chart: wgeChartName,
ReconcileStrategy: sourcev1beta2.ReconcileStrategyChartVersion,
SourceRef: helmv2.CrossNamespaceObjectReference{
Name: wgeHelmRepositoryName,
Namespace: WGEDefaultNamespace,
Namespace: namespace,
},
Version: chartVersion,
},
Expand Down
Loading