Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cli/cmd/apikey/api_key_test_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ func (e *testEnv) GetOmsPortalApiKey() (string, error) {
if e.apiKey == "" {
return "", errors.New("OMS_PORTAL_API_KEY not set in test env")
}

return e.apiKey, nil
}

func (e *testEnv) GetOmsPortalApi() string {
if e.apiURL == "" {
return "https://oms-portal.codesphere.com/api"
}

return e.apiURL
}

func (e *testEnv) GetOmsWorkdir() string {
if e.workdir == "" {
return "./oms-workdir"
}

return e.workdir
}

Expand Down
2 changes: 2 additions & 0 deletions cli/cmd/apikey/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type RegisterOpts struct {

func (c *RegisterCmd) RunE(_ *cobra.Command, args []string) error {
p := portal.NewPortalClient()

newKey, err := c.Register(p)
if err != nil {
return err
Expand Down Expand Up @@ -73,6 +74,7 @@ func (c *RegisterCmd) Register(p portal.Portal) (*portal.ApiKey, error) {
}

var expiresAt time.Time

if c.Opts.ValidFor != "" {
validForDuration, err := intutil.GetDurationFromString(c.Opts.ValidFor)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions cli/cmd/apikey/register_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ var _ = Describe("RegisterCmd", func() {
Context("when valid-for duration is valid", func() {
It("registers the API key successfully", func() {
start := time.Now()

mockPortal.EXPECT().RegisterAPIKey(
owner,
organization,
Expand Down Expand Up @@ -110,6 +111,7 @@ var _ = Describe("RegisterCmd", func() {
Context("when valid-for duration is not provided", func() {
It("passes zero expiration time to portal client", func() {
c.Opts.ValidFor = ""

mockPortal.EXPECT().RegisterAPIKey(owner, organization, role, time.Time{}).Return(&portal.ApiKey{}, nil)

ak, err := c.Register(mockPortal)
Expand All @@ -133,13 +135,16 @@ var _ = Describe("AddRegisterCmd", func() {
parent := &cobra.Command{}
opts := &util.GlobalOptions{}
apikey.AddRegisterCmd(parent, opts)

found := false

for _, c := range parent.Commands() {
if c.Use == "register" {
found = true
break
}
}

Expect(found).To(BeTrue())
})
})
3 changes: 3 additions & 0 deletions cli/cmd/apikey/revoke_api_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ var _ = Describe("AddRevokeAPIKeyCmd", func() {
parent := &cobra.Command{}
opts := &util.GlobalOptions{}
apikey.AddRevokeCmd(parent, opts)

found := false

for _, c := range parent.Commands() {
if c.Use == "api-key" {
found = true
break
}
}

Expect(found).To(BeTrue())
})
})
1 change: 1 addition & 0 deletions cli/cmd/apikey/update_api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ func (c *UpdateAPIKeyCmd) UpdateAPIKey(p portal.Portal) error {
}

log.Printf("Successfully updated API key '%s' with new expiration date %s.\n", c.Opts.APIKeyID, expiresAt.Format(time.RFC1123))

return nil
}
3 changes: 2 additions & 1 deletion cli/cmd/apikey/update_api_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
)

var _ = Describe("UpdateAPIKey", func() {

var (
mockPortal *portal.MockPortal
c apikey.UpdateAPIKeyCmd
Expand All @@ -40,6 +39,7 @@ var _ = Describe("UpdateAPIKey", func() {
RunAndReturn(func(id string, gotExpiresAt time.Time) error {
Expect(id).To(Equal(apiKeyID))
Expect(gotExpiresAt).To(BeTemporally("~", expectedExpiresAt, 5*time.Second))

return nil
})

Expand All @@ -59,6 +59,7 @@ var _ = Describe("UpdateAPIKey", func() {
RunAndReturn(func(id string, gotExpiresAt time.Time) error {
Expect(id).To(Equal(apiKeyID))
Expect(gotExpiresAt).To(BeTemporally("~", expectedExpiresAt, 5*time.Second))

return fmt.Errorf("invalid api key id format")
})

Expand Down
7 changes: 7 additions & 0 deletions cli/cmd/argocd.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func (c *InstallArgoCDCmd) RunE(_ *cobra.Command, args []string) error {
if err != nil {
return err
}

ociPassword = pw
gitPassword = os.Getenv("OMS_GIT_PASSWORD")
}
Expand All @@ -57,6 +58,7 @@ func (c *InstallArgoCDCmd) RunE(_ *cobra.Command, args []string) error {
if err != nil {
return fmt.Errorf("failed to initialize ArgoCD installer: %w", err)
}

err = install.Install()
if err != nil {
return fmt.Errorf("failed to install chart ArgoCD: %w", err)
Expand All @@ -77,14 +79,19 @@ func resolveOCIPassword() (string, error) {
}

fmt.Print("OCI registry password/token: ")

pw, err := term.ReadPassword(int(os.Stdin.Fd()))

fmt.Println()

if err != nil {
return "", fmt.Errorf("failed to read password: %w", err)
}

if len(pw) == 0 {
return "", fmt.Errorf("password is required; set OMS_REGISTRY_PASSWORD or enter it when prompted")
}

return string(pw), nil
}

Expand Down
5 changes: 5 additions & 0 deletions cli/cmd/bootstrap_gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error {
}

c.CodesphereEnv.RegistryType = gcp.RegistryType(c.InputRegistryType)

c.CodesphereEnv.OmsWorkdir = c.Env.GetOmsWorkdir()
if c.CodesphereEnv.GitHubPAT != "" {
c.CodesphereEnv.RegistryType = gcp.RegistryTypeGitHub
Expand Down Expand Up @@ -200,6 +201,7 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error {
if bs.Env.Jumpbox != nil && bs.Env.Jumpbox.GetExternalIP() != "" {
log.Printf("To debug on the jumpbox host:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", bs.Env.Jumpbox.GetExternalIP())
}

return fmt.Errorf("failed to bootstrap GCP: %w", err)
}

Expand All @@ -214,11 +216,14 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error {

packageName := "<package-name>-installer"
installCmd := "oms install codesphere -c /etc/codesphere/config.yaml -k /etc/codesphere/secrets/age_key.txt --vault /etc/codesphere/secrets/prod.vault.yaml"

if gcp.RegistryType(bs.Env.RegistryType) == gcp.RegistryTypeGitHub {
log.Printf("You set a GitHub PAT for direct image access. Make sure to use a lite package, as VM root disk sizes are reduced.")

installCmd += " -s load-container-images"
packageName += "-lite"
}

log.Printf("example install command (run from jumpbox):\n%s -p %s.tar.gz", installCmd, packageName)

return nil
Expand Down
6 changes: 6 additions & 0 deletions cli/cmd/bootstrap_gcp_cleanup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ var _ = Describe("BootstrapGcpCleanupCmd", func() {
Expect(err).NotTo(HaveOccurred())

var decoded gcp.CodesphereEnvironment

err = json.Unmarshal(data, &decoded)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -93,6 +94,7 @@ var _ = Describe("BootstrapGcpCleanupCmd", func() {
Expect(err).NotTo(HaveOccurred())

var decoded gcp.CodesphereEnvironment

err = json.Unmarshal(data, &decoded)
Expect(err).NotTo(HaveOccurred())

Expand Down Expand Up @@ -240,6 +242,7 @@ var _ = Describe("BootstrapGcpCleanupCmd", func() {
Context("when project ID is provided via flag", func() {
It("should use the provided project ID", func() {
cleanupCmd.Opts.ProjectID = "flag-project"

mockFileIO.EXPECT().Exists("/tmp/test-infra.json").Return(false)
mockGCPClient.EXPECT().IsOMSManagedProject("flag-project").Return(false, nil)

Expand All @@ -252,6 +255,7 @@ var _ = Describe("BootstrapGcpCleanupCmd", func() {
Context("when OMS management check fails", func() {
It("should return the verification error", func() {
cleanupCmd.Opts.ProjectID = "test-project"

mockFileIO.EXPECT().Exists("/tmp/test-infra.json").Return(false)
mockGCPClient.EXPECT().IsOMSManagedProject("test-project").Return(false, errors.New("API error"))

Expand All @@ -265,6 +269,7 @@ var _ = Describe("BootstrapGcpCleanupCmd", func() {
It("should skip OMS management check and proceed to confirmation", func() {
cleanupCmd.Opts.ProjectID = "test-project"
cleanupCmd.Opts.Force = true

mockFileIO.EXPECT().Exists("/tmp/test-infra.json").Return(false)
mockGCPClient.EXPECT().DeleteProject("test-project").Return(nil)

Expand All @@ -277,6 +282,7 @@ var _ = Describe("BootstrapGcpCleanupCmd", func() {
It("should abort the cleanup", func() {
cleanupCmd.Opts.ProjectID = "test-project"
deps.ConfirmReader = bytes.NewBufferString("wrong-input\n")

mockFileIO.EXPECT().Exists("/tmp/test-infra.json").Return(false)
mockGCPClient.EXPECT().IsOMSManagedProject("test-project").Return(true, nil)

Expand Down
3 changes: 3 additions & 0 deletions cli/cmd/bootstrap_gcp_postconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ func (c *BootstrapGcpPostconfigCmd) RunE(_ *cobra.Command, args []string) error
fw := intutil.NewFilesystemWriter()

infraFilePath := gcp.GetInfraFilePath()

codesphereEnv, exists, err := gcp.LoadInfraFile(fw, infraFilePath)
if err != nil {
return fmt.Errorf("failed to load gcp infra file: %w", err)
}

if !exists {
return fmt.Errorf("gcp infra file not found at %s", infraFilePath)
}

c.CodesphereEnv = codesphereEnv

err = icg.LoadInstallConfigFromFile(c.Opts.InstallConfigPath)
Expand Down
9 changes: 9 additions & 0 deletions cli/cmd/bootstrap_gcp_restart_vms.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,26 @@ func (c *BootstrapGcpRestartVMsCmd) resolveProjectAndZone(fw intutil.FileIO) (st
if (projectID == "") != (zone == "") {
return "", "", fmt.Errorf("--project-id and --zone must be provided together")
}

if projectID != "" {
return projectID, zone, nil
}

infraFilePath := gcp.GetInfraFilePath()

infraEnv, exists, err := gcp.LoadInfraFile(fw, infraFilePath)
if err != nil {
return "", "", fmt.Errorf("failed to load infra file: %w", err)
}

if !exists {
return "", "", fmt.Errorf("infra file not found at %s; use --project-id and --zone flags", infraFilePath)
}

if infraEnv.ProjectID == "" || infraEnv.Zone == "" {
return "", "", fmt.Errorf("infra file is missing project ID or zone; use --project-id and --zone flags")
}

return infraEnv.ProjectID, infraEnv.Zone, nil
}

Expand Down Expand Up @@ -83,15 +88,19 @@ func (c *BootstrapGcpRestartVMsCmd) RunE(_ *cobra.Command, _ []string) error {

if c.Opts.Name != "" {
log.Printf("Restarting VM %s in project %s (zone %s)...", c.Opts.Name, projectID, zone)

if err := bs.RestartVM(c.Opts.Name); err != nil {
return fmt.Errorf("failed to restart VM: %w", err)
}

log.Printf("VM %s restarted successfully.", c.Opts.Name)
} else {
log.Printf("Restarting all VMs in project %s (zone %s)...", projectID, zone)

if err := bs.RestartVMs(); err != nil {
return fmt.Errorf("failed to restart VMs: %w", err)
}

log.Printf("All VMs restarted successfully.")
}

Expand Down
1 change: 1 addition & 0 deletions cli/cmd/bootstrap_gcp_restart_vms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var _ = Describe("BootstrapGcpRestartVMsCmd", func() {
c, _, err := parentCmd.Find([]string{"restart-vms"})
Expect(err).NotTo(HaveOccurred())
Expect(c).NotTo(BeNil())

return c
}

Expand Down
14 changes: 13 additions & 1 deletion cli/cmd/bootstrap_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ type BootstrapLocalCmd struct {

func (c *BootstrapLocalCmd) RunE(_ *cobra.Command, args []string) error {
err := c.BootstrapLocal()

if err != nil {
return fmt.Errorf("failed to bootstrap: %w", err)
}
Expand Down Expand Up @@ -119,6 +118,7 @@ func (c *BootstrapLocalCmd) BootstrapLocal() error {
if c.CodesphereEnv.InstallConfigPath == "" {
c.CodesphereEnv.InstallConfigPath = filepath.Join(c.CodesphereEnv.InstallDir, "config.yaml")
}

if c.CodesphereEnv.SecretsFilePath == "" {
c.CodesphereEnv.SecretsFilePath = filepath.Join(c.CodesphereEnv.InstallDir, "prod.vault.yaml")
}
Expand All @@ -143,6 +143,7 @@ func (c *BootstrapLocalCmd) BootstrapLocal() error {
stlog := bootstrap.NewStepLogger(false)
icg := installer.NewInstallConfigManager()
fw := intutil.NewFilesystemWriter()

kubeClient, restConfig, err := c.GetKubeClient(ctx)
if err != nil {
return fmt.Errorf("failed to initialize Kubernetes client: %w", err)
Expand All @@ -154,6 +155,7 @@ func (c *BootstrapLocalCmd) BootstrapLocal() error {
}

bs := local.NewLocalBootstrapper(ctx, stlog, kubeClient, restConfig, fw, icg, helmClient, c.CodesphereEnv)

return bs.Bootstrap()
}

Expand All @@ -162,16 +164,23 @@ func (c *BootstrapLocalCmd) resolveRegistryPassword() error {
c.CodesphereEnv.RegistryPassword = pw
return nil
}

fmt.Print("Registry password: ")

pw, err := term.ReadPassword(int(os.Stdin.Fd()))

fmt.Println()

if err != nil {
return fmt.Errorf("failed to read registry password: %w", err)
}

if len(pw) == 0 {
return fmt.Errorf("registry password is required; set OMS_REGISTRY_PASSWORD or enter it when prompted")
}

c.CodesphereEnv.RegistryPassword = string(pw)

return nil
}

Expand Down Expand Up @@ -203,7 +212,9 @@ func (c *BootstrapLocalCmd) ConfirmLocalBootstrapWarning() error {
}

fmt.Print("\nType 'yes' to continue: ")

reader := bufio.NewReader(os.Stdin)

input, err := reader.ReadString('\n')
if err != nil && !errors.Is(err, stdio.EOF) {
return fmt.Errorf("failed to read confirmation: %w", err)
Expand Down Expand Up @@ -243,6 +254,7 @@ func (c *BootstrapLocalCmd) GetKubeClient(ctx context.Context) (ctrlclient.Clien
if err != nil {
return nil, nil, fmt.Errorf("failed to initialize Kubernetes client: %w", err)
}

return kubeClient, kubeConfig, nil
}

Expand Down
1 change: 1 addition & 0 deletions cli/cmd/build_image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ var _ = Describe("AddBuildImageCmd", func() {
cmd.AddBuildImageCmd(parentCmd, globalOpts)

var imageCmd *cobra.Command

for _, c := range parentCmd.Commands() {
if c.Use == "image" {
imageCmd = c
Expand Down
Loading
Loading