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
677 changes: 660 additions & 17 deletions internal/bootstrap/local/ceph.go

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions internal/bootstrap/local/ceph_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) Codesphere Inc.
// SPDX-License-Identifier: Apache-2.0

package local

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
rookcephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
corev1 "k8s.io/api/core/v1"
)

var _ = Describe("Ceph", func() {
Describe("parseMonitorEndpointHost", func() {
DescribeTable("parses monitor endpoint hosts",
func(input, expected string) {
host, err := parseMonitorEndpointHost(input)
Expect(err).NotTo(HaveOccurred())
Expect(host).To(Equal(expected))
},
Entry("plain IP:port", "a=10.0.0.10:6789", "10.0.0.10:6789"),
Entry("msgr2 format", "a=[v2:10.0.0.10:3300/0,v1:10.0.0.10:6789/0]", "10.0.0.10:3300"),
Entry("service DNS with port", "a=rook-ceph-mon-a.rook-ceph.svc:6789", "rook-ceph-mon-a.rook-ceph.svc:6789"),
Entry("service DNS without port", "a=rook-ceph-mon-a.rook-ceph.svc", "rook-ceph-mon-a.rook-ceph.svc"),
)
})

Describe("cephHostsFromObjectStore", func() {
It("parses hosts from a valid object store", func() {
store := &rookcephv1.CephObjectStore{}
store.Name = "s3-ms-provider"
store.Status = &rookcephv1.ObjectStoreStatus{
Endpoints: rookcephv1.ObjectEndpoints{
Insecure: []string{
"http://rook-ceph-rgw-s3-ms-provider.rook-ceph.svc:80",
},
},
}

hosts, err := cephHostsFromObjectStore(store)
Expect(err).NotTo(HaveOccurred())
Expect(hosts).To(HaveLen(1))

expectedHost := "rook-ceph-rgw-s3-ms-provider.rook-ceph.svc"
Expect(hosts[0].Hostname).To(Equal(expectedHost))
Expect(hosts[0].IPAddress).To(Equal(expectedHost))
Expect(hosts[0].IsMaster).To(BeTrue())
})

It("rejects invalid endpoint entries", func() {
store := &rookcephv1.CephObjectStore{}
store.Name = "s3-ms-provider"
store.Status = &rookcephv1.ObjectStoreStatus{
Endpoints: rookcephv1.ObjectEndpoints{
Insecure: []string{"not-a-url"},
},
}

_, err := cephHostsFromObjectStore(store)
Expect(err).To(HaveOccurred())
})
})

Describe("rgwUserCredentialsFromSecret", func() {
It("parses credentials from a valid secret", func() {
secret := &corev1.Secret{}
secret.Name = "rgw-admin-user"
secret.Data = map[string][]byte{
"AccessKey": []byte("access-key"),
"SecretKey": []byte("secret-key"),
}

credentials, err := rgwUserCredentialsFromSecret(secret)
Expect(err).NotTo(HaveOccurred())
Expect(credentials.AccessKey).To(Equal("access-key"))
Expect(credentials.SecretKey).To(Equal("secret-key"))
})

It("rejects secrets with missing keys", func() {
secret := &corev1.Secret{}
secret.Name = "rgw-admin-user"
secret.Data = map[string][]byte{
"username": []byte("foo"),
}

_, err := rgwUserCredentialsFromSecret(secret)
Expect(err).To(HaveOccurred())
})
})

Describe("rgwUserCredentialsFromAdminJSON", func() {
It("parses credentials from valid admin JSON", func() {
credentials, err := rgwUserCredentialsFromAdminJSON(`{"keys":[{"access_key":"access-key","secret_key":"secret-key"}]}`)
Expect(err).NotTo(HaveOccurred())
Expect(credentials.AccessKey).To(Equal("access-key"))
Expect(credentials.SecretKey).To(Equal("secret-key"))
})

It("rejects admin JSON with missing keys", func() {
_, err := rgwUserCredentialsFromAdminJSON(`{"keys":[]}`)
Expect(err).To(HaveOccurred())
})
})
})
2 changes: 1 addition & 1 deletion internal/bootstrap/local/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (

// installerComponentSteps lists the install-components.js steps executed
// locally (in order) instead of running the full private-cloud-installer.
var installerComponentSteps = []string{"setUpCluster", "codesphere"}
var installerComponentSteps = []string{"setUpCluster", "codesphere", "msBackends"}

// installerArtifactFilename is the artifact to download from the OMS portal.
const installerArtifactFilename = "installer-lite.tar.gz"
Expand Down
22 changes: 17 additions & 5 deletions internal/bootstrap/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,13 @@ func (b *LocalBootstrapper) Bootstrap() error {
return err
}

err = b.stlog.Substep("Create Ceph users", b.DeployCephUsers)
err = b.stlog.Substep("Bootstrap RGW gateway", b.DeployRGWGateway)
if err != nil {
return err
}

err = b.stlog.Substep("Read Ceph credentials", func() error {
creds, err := b.ReadCephCredentials()
err = b.stlog.Substep("Ensure Ceph users", func() error {
creds, err := b.EnsureCephUsers()
if err != nil {
return err
}
Expand Down Expand Up @@ -540,10 +540,19 @@ func (b *LocalBootstrapper) UpdateInstallConfig() (err error) {
b.Env.InstallConfig.Cluster.PgOperator = &files.PgOperatorConfig{
Enabled: false,
}
b.Env.InstallConfig.Cluster.RgwLoadBalancer = &files.RgwLoadBalancerConfig{
b.Env.InstallConfig.Cluster.BarmanCloudPlugin = &files.BarmanCloudPluginConfig{
Enabled: false,
}
b.Env.InstallConfig.Ceph = files.CephConfig{}
b.Env.InstallConfig.Cluster.RgwLoadBalancer = &files.RgwLoadBalancerConfig{
Enabled: true,
}
cephMonHosts, err := b.ReadCephMonHosts()
if err != nil {
return fmt.Errorf("failed to read Ceph monitor hosts: %w", err)
}
b.Env.InstallConfig.Ceph = files.CephConfig{
Hosts: cephMonHosts,
}
if b.cephCredentials != nil {
b.addCephSecretsToVault(b.Env.Vault)
}
Expand Down Expand Up @@ -627,13 +636,16 @@ func (b *LocalBootstrapper) EnsureGitHubAccessConfigured() error {
// These mirror the secrets that the JS installer stores via SecretManagerSops:
// - cephFsId (password = FSID)
// - cephfsAdmin, cephfsAdminCodesphere (password = auth key)
// - rgwAdminAccessKey, rgwAdminSecretKey (password = S3 access/secret keys)
// - csiRbdNode, csiRbdProvisioner, csiCephfsNode, csiCephfsProvisioner, csiOperator (password = auth key)
func (b *LocalBootstrapper) addCephSecretsToVault(vault *files.InstallVault) {
creds := b.cephCredentials

vault.SetSecret(files.SecretEntry{Name: "cephFsId", Fields: &files.SecretFields{Password: creds.FSID}})
vault.SetSecret(files.SecretEntry{Name: "cephfsAdmin", Fields: &files.SecretFields{Username: creds.CephfsAdmin.Entity, Password: creds.CephfsAdmin.Key}})
vault.SetSecret(files.SecretEntry{Name: "cephfsAdminCodesphere", Fields: &files.SecretFields{Username: creds.CephfsAdminCodesphere.Entity, Password: creds.CephfsAdminCodesphere.Key}})
vault.SetSecret(files.SecretEntry{Name: "rgwAdminAccessKey", Fields: &files.SecretFields{Password: creds.RGWAdmin.AccessKey}})
vault.SetSecret(files.SecretEntry{Name: "rgwAdminSecretKey", Fields: &files.SecretFields{Password: creds.RGWAdmin.SecretKey}})
vault.SetSecret(files.SecretEntry{Name: "csiRbdNode", Fields: &files.SecretFields{Username: creds.CSIRBDNode.Entity, Password: creds.CSIRBDNode.Key}})
vault.SetSecret(files.SecretEntry{Name: "csiRbdProvisioner", Fields: &files.SecretFields{Username: creds.CSIRBDProvisioner.Entity, Password: creds.CSIRBDProvisioner.Key}})
vault.SetSecret(files.SecretEntry{Name: "csiCephfsNode", Fields: &files.SecretFields{Username: creds.CSICephFSNode.Entity, Password: creds.CSICephFSNode.Key}})
Expand Down
16 changes: 16 additions & 0 deletions internal/bootstrap/local/local_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Codesphere Inc.
// SPDX-License-Identifier: Apache-2.0

package local

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestLocal(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Bootstrap Local Suite")
}
5 changes: 4 additions & 1 deletion internal/bootstrap/local/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ func (b *LocalBootstrapper) InstallCloudNativePGHelmChart() error {
CreateNamespace: true,
Values: map[string]interface{}{
"config": map[string]interface{}{
"clusterWide": false,
"clusterWide": true,
"data": map[string]interface{}{
"INHERITED_LABELS": "teamId",
},
},
"resources": map[string]interface{}{
"requests": map[string]interface{}{
Expand Down
4 changes: 2 additions & 2 deletions internal/installer/config_manager_profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,10 @@ func (g *InstallConfig) applyCommonProperties() {
}
if g.Config.ManagedServiceBackends == nil {
g.Config.ManagedServiceBackends = &files.ManagedServiceBackendsConfig{
Postgres: make(map[string]interface{}),
Postgres: &files.PgManagedServiceConfig{},
}
} else if g.Config.ManagedServiceBackends.Postgres == nil {
g.Config.ManagedServiceBackends.Postgres = make(map[string]interface{})
g.Config.ManagedServiceBackends.Postgres = &files.PgManagedServiceConfig{}
}
if g.Config.Codesphere.ManagedServices == nil {
g.Config.Codesphere.ManagedServices = []files.ManagedServiceConfig{
Expand Down
28 changes: 25 additions & 3 deletions internal/installer/files/config_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,13 @@ type K8sNode struct {
type ClusterConfig struct {
Certificates ClusterCertificates `yaml:"certificates"`
CertManager *CertManagerConfig `yaml:"certManager,omitempty"`
TrustManager *TrustManagerConfig `yaml:"trustManager,omitempty"`
Monitoring *MonitoringConfig `yaml:"monitoring,omitempty"`
Gateway GatewayConfig `yaml:"gateway"`
PublicGateway GatewayConfig `yaml:"publicGateway"`
RookExternalCluster *RookExternalClusterConfig `yaml:"rookExternalCluster,omitempty"`
PgOperator *PgOperatorConfig `yaml:"pgOperator,omitempty"`
BarmanCloudPlugin *BarmanCloudPluginConfig `yaml:"BarmanCloudPluginConfig,omitempty"`
RgwLoadBalancer *RgwLoadBalancerConfig `yaml:"rgwLoadBalancer,omitempty"`

IngressCAKey string `yaml:"-"`
Expand Down Expand Up @@ -237,16 +239,27 @@ type CertManagerConfig struct {
Override ChartOverride `yaml:"override,omitempty"`
}

type TrustManagerConfig struct {
Override ChartOverride `yaml:"override,omitempty"`
}

type RookExternalClusterConfig struct {
Enabled bool `yaml:"enabled"`
}

type PgOperatorConfig struct {
Enabled bool `yaml:"enabled"`
Enabled bool `yaml:"enabled"`
Override ChartOverride `yaml:"override,omitempty"`
}

type BarmanCloudPluginConfig struct {
Enabled bool `yaml:"enabled"`
Override ChartOverride `yaml:"override,omitempty"`
}

type RgwLoadBalancerConfig struct {
Enabled bool `yaml:"enabled"`
Enabled bool `yaml:"enabled"`
Override ChartOverride `yaml:"override,omitempty"`
}

type MetalLBConfig struct {
Expand Down Expand Up @@ -507,7 +520,8 @@ type PlanParam struct {
}

type ManagedServiceBackendsConfig struct {
Postgres map[string]interface{} `yaml:"postgres,omitempty"`
Postgres *PgManagedServiceConfig `yaml:"postgres,omitempty"`
S3 *S3ManagedServiceConfig `yaml:"s3,omitempty"`
}

type MonitoringConfig struct {
Expand Down Expand Up @@ -563,6 +577,14 @@ type MetalLBPool struct {
IPAddresses []string
}

type PgManagedServiceConfig struct {
Override ChartOverride `yaml:"override,omitempty"`
}

type S3ManagedServiceConfig struct {
Override ChartOverride `yaml:"override,omitempty"`
}

// Marshal serializes the RootConfig to YAML
func (c *RootConfig) Marshal() ([]byte, error) {
return yaml.Marshal(c)
Expand Down
66 changes: 66 additions & 0 deletions internal/installer/resource_profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ func applyNoRequestsProfile(config *files.RootConfig) {
},
})

if config.Cluster.TrustManager == nil {
config.Cluster.TrustManager = &files.TrustManagerConfig{}
}
config.Cluster.TrustManager.Override = util.DeepMergeMaps(config.Cluster.TrustManager.Override, map[string]any{
"trust-manager": map[string]any{
"resources": map[string]any{
"requests": zeroRequests(),
},
},
})

if config.Cluster.Monitoring == nil {
config.Cluster.Monitoring = &files.MonitoringConfig{}
}
Expand Down Expand Up @@ -159,6 +170,61 @@ func applyNoRequestsProfile(config *files.RootConfig) {
},
})

if config.Cluster.PgOperator == nil {
config.Cluster.PgOperator = &files.PgOperatorConfig{}
}
config.Cluster.PgOperator.Override = util.DeepMergeMaps(config.Cluster.PgOperator.Override, map[string]any{
"cloudnative-pg": map[string]any{
"config": map[string]any{
"clusterWide": false,
},
"resources": map[string]any{
"requests": zeroRequests(),
},
},
})

if config.Cluster.BarmanCloudPlugin == nil {
config.Cluster.BarmanCloudPlugin = &files.BarmanCloudPluginConfig{}
}
config.Cluster.BarmanCloudPlugin.Override = util.DeepMergeMaps(config.Cluster.BarmanCloudPlugin.Override, map[string]any{
"plugin-barman-cloud": map[string]any{
"resources": map[string]any{
"requests": zeroRequests(),
},
},
})

if config.Cluster.RgwLoadBalancer == nil {
config.Cluster.RgwLoadBalancer = &files.RgwLoadBalancerConfig{}
}
config.Cluster.RgwLoadBalancer.Override = util.DeepMergeMaps(config.Cluster.RgwLoadBalancer.Override, map[string]any{
"replicas": 1,
})

if config.ManagedServiceBackends == nil {
config.ManagedServiceBackends = &files.ManagedServiceBackendsConfig{}
}
if config.ManagedServiceBackends.Postgres == nil {
config.ManagedServiceBackends.Postgres = &files.PgManagedServiceConfig{}
}
config.ManagedServiceBackends.Postgres.Override = util.DeepMergeMaps(config.ManagedServiceBackends.Postgres.Override, map[string]any{
"replicas": 1,
"resources": map[string]any{
"requests": zeroRequests(),
},
})

if config.ManagedServiceBackends.S3 == nil {
config.ManagedServiceBackends.S3 = &files.S3ManagedServiceConfig{}
}
config.ManagedServiceBackends.S3.Override = util.DeepMergeMaps(config.ManagedServiceBackends.S3.Override, map[string]any{
"replicas": 1,
"resources": map[string]any{
"requests": zeroRequests(),
},
})

serviceProfiles := map[string]any{}
for _, serviceName := range []string{
"auth_service",
Expand Down
Loading
Loading