Skip to content
Merged
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
6 changes: 5 additions & 1 deletion cli/cmd/bootstrap_gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ func AddBootstrapGcpCmd(parent *cobra.Command, opts *GlobalOptions) {
flags.StringArrayVar(&bootstrapGcpCmd.CodesphereEnv.Experiments, "experiments", gcp.DefaultExperiments, "Experiments to enable in Codesphere installation (optional)")
flags.StringArrayVar(&bootstrapGcpCmd.CodesphereEnv.FeatureFlags, "feature-flags", []string{}, "Feature flags to enable in Codesphere installation (optional)")

flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.OpenBaoURI, "openbao-uri", "", "URI for OpenBao (optional)")
flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.OpenBaoEngine, "openbao-engine", "cs-secrets-engine", "OpenBao engine name (default: cs-secrets-engine)")
flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.OpenBaoUser, "openbao-user", "admin", "OpenBao username (optional)")
flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.OpenBaoPassword, "openbao-password", "", "OpenBao password (optional)")

util.MarkFlagRequired(bootstrapGcpCmd.cmd, "project-name")
util.MarkFlagRequired(bootstrapGcpCmd.cmd, "billing-account")
util.MarkFlagRequired(bootstrapGcpCmd.cmd, "base-domain")
Expand Down Expand Up @@ -143,7 +148,6 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error {
}

log.Println("\n🎉🎉🎉 GCP infrastructure bootstrapped successfully!")
log.Println(envString)
log.Printf("Infrastructure details written to %s", infraFilePath)
log.Printf("Access the jumpbox using:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", bs.Env.Jumpbox.GetExternalIP())
if bs.Env.InstallVersion != "" {
Expand Down
20 changes: 20 additions & 0 deletions cli/cmd/init_install_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ type InitInstallConfigOpts struct {
CodesphereHostingPlanTempStorageMb int
CodesphereWorkspacePlanName string
CodesphereWorkspacePlanMaxReplicas int

CodesphereOpenBaoUri string
CodesphereOpenBaoEngine string
CodesphereOpenBaoUser string
CodesphereOpenBaoPassword string
}

func (c *InitInstallConfigCmd) RunE(_ *cobra.Command, args []string) error {
Expand Down Expand Up @@ -154,6 +159,11 @@ func AddInitInstallConfigCmd(init *cobra.Command, opts *GlobalOptions) {

c.cmd.Flags().StringVar(&c.Opts.CodesphereDomain, "domain", "", "Main Codesphere domain")

c.cmd.Flags().StringVar(&c.Opts.CodesphereOpenBaoUri, "openbao-uri", "", "URI for OpenBao (e.g., https://openbao.example.com)")
c.cmd.Flags().StringVar(&c.Opts.CodesphereOpenBaoEngine, "openbao-engine", "cs-secrets-engine", "Engine for OpenBao")
c.cmd.Flags().StringVar(&c.Opts.CodesphereOpenBaoUser, "openbao-user", "admin", "Username for OpenBao authentication")
c.cmd.Flags().StringVar(&c.Opts.CodesphereOpenBaoPassword, "openbao-password", "", "Password for OpenBao authentication")

util.MarkFlagRequired(c.cmd, "config")
util.MarkFlagRequired(c.cmd, "vault")

Expand Down Expand Up @@ -448,6 +458,16 @@ func (c *InitInstallConfigCmd) updateConfigFromOpts(config *files.RootConfig) *f
}
}

if c.Opts.CodesphereOpenBaoUri != "" {
if config.Codesphere.OpenBao == nil {
config.Codesphere.OpenBao = &files.OpenBaoConfig{}
}
config.Codesphere.OpenBao.URI = c.Opts.CodesphereOpenBaoUri
config.Codesphere.OpenBao.Engine = c.Opts.CodesphereOpenBaoEngine
config.Codesphere.OpenBao.User = c.Opts.CodesphereOpenBaoUser
config.Codesphere.OpenBao.Password = c.Opts.CodesphereOpenBaoPassword
}

// Plans
if c.Opts.CodesphereHostingPlanCPUTenth != 0 || c.Opts.CodesphereHostingPlanMemoryMb != 0 ||
c.Opts.CodesphereHostingPlanStorageMb != 0 || c.Opts.CodesphereHostingPlanTempStorageMb != 0 {
Expand Down
4 changes: 4 additions & 0 deletions docs/oms-cli_beta_bootstrap-gcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ oms-cli beta bootstrap-gcp [flags]
--install-hash string Codesphere package hash to install (default: none)
-s, --install-skip-steps stringArray Installation steps to skip during Codesphere installation (optional)
--install-version string Codesphere version to install (default: none)
--openbao-engine string OpenBao engine name (default: cs-secrets-engine) (default "cs-secrets-engine")
--openbao-password string OpenBao password (optional)
--openbao-uri string URI for OpenBao (optional)
--openbao-user string OpenBao username (optional) (default "admin")
--preemptible Use preemptible VMs for Codesphere infrastructure (default: false)
--project-name string Unique GCP Project Name (required)
--region string GCP Region (default: europe-west4) (default "europe-west4")
Expand Down
4 changes: 4 additions & 0 deletions docs/oms-cli_init_install-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ $ oms-cli init install-config --validate -c config.yaml --vault prod.vault.yaml
--interactive Enable interactive prompting (when true, other config flags are ignored) (default true)
--k8s-control-plane strings K8s control plane IPs (comma-separated)
--k8s-managed Use Codesphere-managed Kubernetes (default true)
--openbao-engine string Engine for OpenBao (default "cs-secrets-engine")
--openbao-password string Password for OpenBao authentication
--openbao-uri string URI for OpenBao (e.g., https://openbao.example.com)
--openbao-user string Username for OpenBao authentication (default "admin")
--postgres-mode string PostgreSQL setup mode (install/external)
--postgres-primary-ip string Primary PostgreSQL server IP
--profile string Use a predefined configuration profile (dev, production, minimal)
Expand Down
30 changes: 30 additions & 0 deletions internal/bootstrap/gcp/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ type CodesphereEnvironment struct {
Experiments []string `json:"experiments"`
FeatureFlags []string `json:"feature_flags"`

// OpenBao
OpenBaoURI string `json:"-"`
OpenBaoEngine string `json:"-"`
OpenBaoUser string `json:"-"`
OpenBaoPassword string `json:"-"`

// Config
InstallConfigPath string `json:"-"`
SecretsFilePath string `json:"-"`
Expand Down Expand Up @@ -1271,6 +1277,30 @@ func (b *GCPBootstrapper) UpdateInstallConfig() error {
}
}

b.Env.InstallConfig.Codesphere.ManagedServices = []files.ManagedServiceConfig{
{
Name: "postgres",
Version: "v1",
},
{
Name: "babelfish",
Version: "v1",
},
{
Name: "s3",
Version: "v1",
},
}

if b.Env.OpenBaoURI != "" {
b.Env.InstallConfig.Codesphere.OpenBao = &files.OpenBaoConfig{
Engine: b.Env.OpenBaoEngine,
URI: b.Env.OpenBaoURI,
User: b.Env.OpenBaoUser,
Password: b.Env.OpenBaoPassword,
}
}

if err := b.icg.WriteInstallConfig(b.Env.InstallConfigPath, true); err != nil {
return fmt.Errorf("failed to write config file: %w", err)
}
Expand Down
27 changes: 27 additions & 0 deletions internal/bootstrap/gcp/gcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,9 @@ var _ = Describe("GCP Bootstrapper", func() {
dnsConfig := dnsIssuer["config"].(map[string]interface{})
cloudDns := dnsConfig["cloudDNS"].(map[string]interface{})
Expect(cloudDns["project"]).To(Equal(bs.Env.DNSProjectID))

Expect(bs.Env.InstallConfig.Codesphere.OpenBao).To(BeNil())
Expect(len(bs.Env.InstallConfig.Codesphere.ManagedServices)).To(Equal(3))
})
Context("When Experiments are set in CodesphereEnvironment", func() {
BeforeEach(func() {
Expand Down Expand Up @@ -1190,6 +1193,30 @@ var _ = Describe("GCP Bootstrapper", func() {
})

})

Context("When OpenBao config is set", func() {
BeforeEach(func() {
csEnv.OpenBaoURI = "https://openbao.example.com"
csEnv.OpenBaoPassword = "fake-password"
csEnv.OpenBaoUser = "fake-username"
csEnv.OpenBaoEngine = "fake-engine"
})
It("sets OpenBao config in install config", func() {
icg.EXPECT().GenerateSecrets().Return(nil)
icg.EXPECT().WriteInstallConfig("fake-config-file", true).Return(nil)
icg.EXPECT().WriteVault("fake-secret", true).Return(nil)

nodeClient.EXPECT().CopyFile(mock.Anything, mock.Anything, mock.Anything).Return(nil).Twice()

err := bs.UpdateInstallConfig()
Expect(err).NotTo(HaveOccurred())

Expect(bs.Env.InstallConfig.Codesphere.OpenBao.URI).To(Equal("https://openbao.example.com"))
Expect(bs.Env.InstallConfig.Codesphere.OpenBao.Password).To(Equal("fake-password"))
Expect(bs.Env.InstallConfig.Codesphere.OpenBao.User).To(Equal("fake-username"))
Expect(bs.Env.InstallConfig.Codesphere.OpenBao.Engine).To(Equal("fake-engine"))
})
})
})

Describe("Invalid cases", func() {
Expand Down
20 changes: 20 additions & 0 deletions internal/installer/config_generator_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,24 @@ func (g *InstallConfig) collectCodesphereConfig(prompter *Prompter) {
1: workspacePlan,
},
}

g.collectOpenBaoConfig(prompter)
}

func (g *InstallConfig) collectOpenBaoConfig(prompter *Prompter) {
log.Println("\n=== OpenBao Configuration (Optional) ===")
hasOpenBao := prompter.Bool("Configure OpenBao integration", g.Config.Codesphere.OpenBao != nil && g.Config.Codesphere.OpenBao.URI != "")
if !hasOpenBao {
g.Config.Codesphere.OpenBao = nil
return
}

if g.Config.Codesphere.OpenBao == nil {
g.Config.Codesphere.OpenBao = &files.OpenBaoConfig{}
}

g.Config.Codesphere.OpenBao.URI = g.collectString(prompter, "OpenBao URI (e.g., https://openbao.example.com)", "")
g.Config.Codesphere.OpenBao.Engine = g.collectString(prompter, "OpenBao engine name", "cs-secrets-engine")
g.Config.Codesphere.OpenBao.User = g.collectString(prompter, "OpenBao username", "admin")
g.Config.Codesphere.OpenBao.Password = g.collectString(prompter, "OpenBao password", "")
}
29 changes: 29 additions & 0 deletions internal/installer/config_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io"
"net"
"net/url"

"github.com/codesphere-cloud/oms/internal/installer/files"
"github.com/codesphere-cloud/oms/internal/util"
Expand Down Expand Up @@ -155,6 +156,21 @@ func (g *InstallConfig) ValidateInstallConfig() []string {
errors = append(errors, "Codesphere domain is required")
}

if g.Config.Codesphere.OpenBao != nil {
if g.Config.Codesphere.OpenBao.URI == "" {
errors = append(errors, "OpenBao URI is required when OpenBao integration is enabled")
}
if _, err := url.ParseRequestURI(g.Config.Codesphere.OpenBao.URI); err != nil {
errors = append(errors, "OpenBao URI must be a valid URL")
}
if g.Config.Codesphere.OpenBao.Engine == "" {
errors = append(errors, "OpenBao engine name is required when OpenBao integration is enabled")
}
if g.Config.Codesphere.OpenBao.User == "" {
errors = append(errors, "OpenBao username is required when OpenBao integration is enabled")
}
}

return errors
}

Expand All @@ -177,6 +193,12 @@ func (g *InstallConfig) ValidateVault() []string {
}
}

if g.Config.Codesphere.OpenBao != nil {
if !foundSecrets["openBaoPassword"] {
errors = append(errors, "required OpenBao secret missing: openBaoPassword")
}
}

return errors
}

Expand Down Expand Up @@ -358,5 +380,12 @@ func (g *InstallConfig) MergeVaultIntoConfig() error {
}
}

// OpenBao secrets
if g.Config.Codesphere.OpenBao != nil {
if secret, ok := secretsMap["openBaoPassword"]; ok && secret.Fields != nil {
g.Config.Codesphere.OpenBao.Password = secret.Fields.Password
}
}

return nil
}
45 changes: 45 additions & 0 deletions internal/installer/config_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,51 @@ var _ = Describe("ConfigManager", func() {
Expect(errors).To(ContainElement(ContainSubstring("postgres server address is required")))
})
})

})

Context("openBao validation", func() {
BeforeEach(func() {
configManager.Config.Codesphere.OpenBao = &files.OpenBaoConfig{
URI: "https://openbao.example.com",
Engine: "openbao-engine",
User: "fake-user",
}
})

It("should require OpenBao URI", func() {
configManager.Config.Codesphere.OpenBao.URI = ""
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("OpenBao URI is required")))
})

It("should require OpenBao engine", func() {
configManager.Config.Codesphere.OpenBao.Engine = ""
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("OpenBao engine name is required")))
})

It("should require OpenBao user", func() {
configManager.Config.Codesphere.OpenBao.User = ""
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("OpenBao username is required")))
})

It("should validate OpenBao URI format", func() {
configManager.Config.Codesphere.OpenBao.URI = "not-a-valid-url"
errors := configManager.ValidateInstallConfig()
Expect(errors).To(ContainElement(ContainSubstring("OpenBao URI must be a valid URL")))
})

It("should require OpenBao password in vault", func() {
configManager.Vault = &files.InstallVault{
Secrets: []files.SecretEntry{
{Name: "cephSshPrivateKey"},
},
}
errors := configManager.ValidateVault()
Expect(errors).To(ContainElement(ContainSubstring("required OpenBao secret missing: openBaoPassword")))
})
})

Context("ceph validation", func() {
Expand Down
41 changes: 31 additions & 10 deletions internal/installer/files/config_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,20 @@ type CodesphereConfig struct {
UnderprovisionFactors *UnderprovisionFactors `yaml:"underprovisionFactors,omitempty"`
GitProviders *GitProvidersConfig `yaml:"gitProviders,omitempty"`
ManagedServices []ManagedServiceConfig `yaml:"managedServices,omitempty"`
OpenBao *OpenBaoConfig `yaml:"openBao,omitempty"`

DomainAuthPrivateKey string `yaml:"-"`
DomainAuthPublicKey string `yaml:"-"`
}

type OpenBaoConfig struct {
Engine string `yaml:"engine,omitempty"`
URI string `yaml:"uri,omitempty"`
User string `yaml:"user,omitempty"`

Password string `yaml:"-"`
}

type CertIssuerType string

const (
Expand Down Expand Up @@ -417,16 +426,16 @@ type OAuthConfig struct {

type ManagedServiceConfig struct {
Name string `yaml:"name"`
API ManagedServiceAPI `yaml:"api"`
Author string `yaml:"author"`
Category string `yaml:"category"`
ConfigSchema map[string]interface{} `yaml:"configSchema"`
DetailsSchema map[string]interface{} `yaml:"detailsSchema"`
SecretsSchema map[string]interface{} `yaml:"secretsSchema"`
Description string `yaml:"description"`
DisplayName string `yaml:"displayName"`
IconURL string `yaml:"iconUrl"`
Plans []ServicePlan `yaml:"plans"`
API ManagedServiceAPI `yaml:"api,omitempty"`
Author string `yaml:"author,omitempty"`
Category string `yaml:"category,omitempty"`
ConfigSchema map[string]interface{} `yaml:"configSchema,omitempty"`
DetailsSchema map[string]interface{} `yaml:"detailsSchema,omitempty"`
SecretsSchema map[string]interface{} `yaml:"secretsSchema,omitempty"`
Description string `yaml:"description,omitempty"`
DisplayName string `yaml:"displayName,omitempty"`
IconURL string `yaml:"iconUrl,omitempty"`
Plans []ServicePlan `yaml:"plans,omitempty"`
Version string `yaml:"version"`
}

Expand Down Expand Up @@ -530,6 +539,7 @@ func (c *RootConfig) ExtractVault() *InstallVault {
c.addManagedServiceSecrets(vault)
c.addRegistrySecrets(vault)
c.addKubeConfigSecret(vault)
c.addOpenBaoSecrets(vault)

return vault
}
Expand Down Expand Up @@ -744,6 +754,17 @@ func (c *RootConfig) addKubeConfigSecret(vault *InstallVault) {
}
}

func (c *RootConfig) addOpenBaoSecrets(vault *InstallVault) {
if c.Codesphere.OpenBao != nil && c.Codesphere.OpenBao.Password != "" {
vault.Secrets = append(vault.Secrets, SecretEntry{
Name: "openBaoPassword",
Fields: &SecretFields{
Password: c.Codesphere.OpenBao.Password,
},
})
}
}

func Capitalize(s string) string {
if s == "" {
return ""
Expand Down