Skip to content

Commit

Permalink
Improved support for CAO deployments.
Browse files Browse the repository at this point in the history
  • Loading branch information
brett19 committed Jan 30, 2024
1 parent e1097eb commit aed7a49
Show file tree
Hide file tree
Showing 14 changed files with 414 additions and 42 deletions.
9 changes: 9 additions & 0 deletions clusterdef/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Cluster struct {
NodeGroups []*NodeGroup `yaml:"nodes,omitempty"`

Docker DockerCluster `yaml:"docker,omitempty"`
Cao CaoCluster `yaml:"cao,omitempty"`
Cloud CloudCluster `yaml:"cloud,omitempty"`
}

Expand All @@ -25,6 +26,14 @@ type DockerCluster struct {
EventingMemoryMB int `yaml:"eventing-memory,omitempty"`
}

type CaoCluster struct {
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`

OperatorVersion string `yaml:"operator-version,omitempty"`
GatewayVersion string `yaml:"gateway-version,omitempty"`
}

type CloudCluster struct {
CloudProvider string `yaml:"cloud-provider,omitempty"`
Region string `yaml:"region,omitempty"`
Expand Down
32 changes: 32 additions & 0 deletions cmd/certificates-getgatewayca.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"
"go.uber.org/zap"
)

var certificatesGetGatewayCaCmd = &cobra.Command{
Use: "get-gateway-ca",
Short: "Fetches the Gateway CA certificate",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
helper := CmdHelper{}
logger := helper.GetLogger()
ctx := helper.GetContext()

_, deployer, cluster := helper.IdentifyCluster(ctx, args[0])

cert, err := deployer.GetGatewayCertificate(ctx, cluster.GetID())
if err != nil {
logger.Fatal("failed to get gateway certificate", zap.Error(err))
}

fmt.Printf("%s\n", cert)
},
}

func init() {
certificatesCmd.AddCommand(certificatesGetGatewayCaCmd)
}
41 changes: 27 additions & 14 deletions cmd/connstr.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var connstrCmd = &cobra.Command{

useTLS, _ := cmd.Flags().GetBool("tls")
noTLS, _ := cmd.Flags().GetBool("no-tls")
useCb2, _ := cmd.Flags().GetBool("couchbase2")

_, deployer, cluster := helper.IdentifyCluster(ctx, args[0])

Expand All @@ -28,25 +29,36 @@ var connstrCmd = &cobra.Command{
}

var connStr string
if useTLS && noTLS {
logger.Fatal("cannot request both TLS and non-TLS")
} else if useTLS {
connStr = connectInfo.ConnStrTls
if connStr == "" {
logger.Fatal("TLS endpoint is unavailable")
if useCb2 {
if noTLS {
logger.Fatal("cannot request non-TLS for couchbase2")
}
} else if noTLS {
connStr = connectInfo.ConnStr

connStr = connectInfo.ConnStrCb2
if connStr == "" {
logger.Fatal("non-TLS endpoint is unavailable")
logger.Fatal("couchbase2 endpoint is unavailable")
}
} else {
connStr = connectInfo.ConnStr
if connStr == "" {
if useTLS && noTLS {
logger.Fatal("cannot request both TLS and non-TLS")
} else if useTLS {
connStr = connectInfo.ConnStrTls
}
if connStr == "" {
logger.Fatal("no endpoint available")
if connStr == "" {
logger.Fatal("TLS endpoint is unavailable")
}
} else if noTLS {
connStr = connectInfo.ConnStr
if connStr == "" {
logger.Fatal("non-TLS endpoint is unavailable")
}
} else {
connStr = connectInfo.ConnStr
if connStr == "" {
connStr = connectInfo.ConnStrTls
}
if connStr == "" {
logger.Fatal("no endpoint available")
}
}
}

Expand All @@ -57,6 +69,7 @@ var connstrCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(connstrCmd)

connstrCmd.PersistentFlags().Bool("couchbase2", false, "Requests a couchbase2 connstr")
connstrCmd.PersistentFlags().Bool("tls", false, "Explicitly requests a TLS endpoint")
connstrCmd.PersistentFlags().Bool("no-tls", false, "Explicitly requests non-TLS endpoint")
}
2 changes: 1 addition & 1 deletion cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ var initCmd = &cobra.Command{

if shouldInstallAdm {
fmt.Printf("---- admission controller install start ----\n")
err := caoCtrl.InstallGlobalAdmissionController(ctx, "")
err := caoCtrl.InstallGlobalAdmissionController(ctx, "", "")
fmt.Printf("---- admission controller install end ----\n")
if err != nil {
fmt.Printf("Failed to install Admission Controller:\n %s\n", err)
Expand Down
4 changes: 3 additions & 1 deletion cmd/tools-cao-installadmission.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ var toolsCaoInstallAdmissionCmd = &cobra.Command{
caoDeployer := helper.GetCaoDeployer(ctx)

namespace, _ := cmd.Flags().GetString("namespace")
version, _ := cmd.Flags().GetString("version")

err := caoDeployer.GetClient().InstallGlobalAdmissionController(ctx, namespace)
err := caoDeployer.GetClient().InstallGlobalAdmissionController(ctx, namespace, version)
if err != nil {
logger.Fatal("failed to install admission controller", zap.Error(err))
}
Expand All @@ -27,4 +28,5 @@ func init() {
toolsCaoCmd.AddCommand(toolsCaoInstallAdmissionCmd)

toolsCaoInstallAdmissionCmd.Flags().String("namespace", "", "Which namespace to install in.")
toolsCaoInstallAdmissionCmd.Flags().String("version", "", "Which admission controller version to install.")
}
117 changes: 97 additions & 20 deletions deployment/caodeploy/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,48 @@ func (d *Deployer) ListClusters(ctx context.Context) ([]deployment.ClusterInfo,
}

func (d *Deployer) NewCluster(ctx context.Context, def *clusterdef.Cluster) (deployment.ClusterInfo, error) {
clusterID := cbdcuuid.New()
clusterVersion := ""
for _, nodeGrp := range def.NodeGroups {
if clusterVersion == "" {
clusterVersion = nodeGrp.Version
}
if clusterVersion != nodeGrp.Version {
return nil, errors.New("all node groups must have the same couchbase version")
}
}

serverImagePath, err := caocontrol.GetServerImage(ctx, clusterVersion)
if err != nil {
return nil, errors.Wrap(err, "failed to identify server image")
}

gatewayImagePath := ""
if def.Cao.GatewayVersion != "" {
foundGatewayImagePath, err := caocontrol.GetGatewayImage(ctx, def.Cao.GatewayVersion)
if err != nil {
return nil, errors.Wrap(err, "failed to identify gateway image")
}

gatewayImagePath = foundGatewayImagePath
}
username := "Administrator"
password := "password"
if def.Docker.Username != "" {
username = def.Cao.Username
}
if def.Docker.Password != "" {
password = def.Cao.Password
}

clusterID := cbdcuuid.New()
namespace := "cbdc2-" + clusterID.String()

expiryTime := time.Time{}
if def.Expiry > 0 {
expiryTime = time.Now().Add(def.Expiry)
}

err := d.client.CreateNamespace(ctx, namespace, map[string]string{
err = d.client.CreateNamespace(ctx, namespace, map[string]string{
"cbdc2.type": "cluster",
"cbdc2.cluster_id": clusterID.String(),
"cbdc2.purpose": def.Purpose,
Expand All @@ -136,32 +168,23 @@ func (d *Deployer) NewCluster(ctx context.Context, def *clusterdef.Cluster) (dep
return nil, errors.Wrap(err, "failed to install ghcr secret")
}

err = d.client.InstallOperator(ctx, namespace)
err = d.client.InstallOperator(ctx, namespace, def.Cao.OperatorVersion)
if err != nil {
return nil, errors.Wrap(err, "failed to install operator")
}

err = d.client.CreateBasicAuthSecret(ctx, namespace, "cbdc2-admin-auth", "Administrator", "password")
err = d.client.CreateBasicAuthSecret(ctx, namespace, "cbdc2-admin-auth", username, password)
if err != nil {
return nil, errors.Wrap(err, "failed to create admin auth")
}

clusterVersion := ""

var serversRes []interface{}
for nodeGrpIdx, nodeGrp := range def.NodeGroups {
caoServices, err := clusterdef.ServicesToCaoServices(nodeGrp.Services)
if err != nil {
return nil, errors.Wrap(err, "failed to generate cao server services list")
}

if clusterVersion == "" {
clusterVersion = nodeGrp.Version
}
if clusterVersion != nodeGrp.Version {
return nil, errors.New("all node groups must have the same couchbase version")
}

serversRes = append(serversRes, map[string]interface{}{
"size": nodeGrp.Count,
"name": fmt.Sprintf("group_%d", nodeGrpIdx),
Expand All @@ -178,8 +201,15 @@ func (d *Deployer) NewCluster(ctx context.Context, def *clusterdef.Cluster) (dep
})
}

var cngSpec map[string]interface{}
if gatewayImagePath != "" {
cngSpec = map[string]interface{}{
"image": gatewayImagePath,
}
}

clusterSpec := map[string]interface{}{
"image": "couchbase/server:" + clusterVersion,
"image": serverImagePath,
"buckets": map[string]interface{}{
"managed": false,
},
Expand All @@ -192,15 +222,30 @@ func (d *Deployer) NewCluster(ctx context.Context, def *clusterdef.Cluster) (dep
"networking": map[string]interface{}{
"exposeAdminConsole": true,
"exposedFeatures": []string{"admin", "xdcr", "client"},
"cloudNativeGateway": cngSpec,
},
"servers": serversRes,
}

err = d.client.CreateCouchbaseCluster(ctx, namespace, CouchbaseClusterName, nil, clusterSpec)
err = d.client.CreateCouchbaseCluster(ctx,
namespace, CouchbaseClusterName, nil,
clusterSpec)
if err != nil {
return nil, errors.Wrap(err, "failed to create cluster resource")
}

// check if the CNG service is there, if so, lets mirror it to a cbdc NodePort
_, err = d.client.GetService(ctx, namespace, CouchbaseClusterName+"-cloud-native-gateway-service")
if err != nil {
d.logger.Info("no cng service detected")
} else {
d.logger.Info("cng service detected, creating NodePort service")
err = d.client.CreateCbdcCngService(ctx, namespace, CouchbaseClusterName)
if err != nil {
return nil, errors.Wrap(err, "failed to create dino cng service")
}
}

return ClusterInfo{
ClusterID: clusterID.String(),
Expiry: time.Time{},
Expand Down Expand Up @@ -281,11 +326,6 @@ func (d *Deployer) GetConnectInfo(ctx context.Context, clusterID string) (*deplo
return nil, err
}

service, err := d.client.GetService(ctx, namespaceName, CouchbaseClusterName+"-ui")
if err != nil {
return nil, errors.Wrap(err, "failed to get service")
}

nodes, err := d.client.GetNodes(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to get nodes")
Expand All @@ -307,6 +347,11 @@ func (d *Deployer) GetConnectInfo(ctx context.Context, clusterID string) (*deplo
return nil, errors.New("could not identify node IP to use")
}

service, err := d.client.GetService(ctx, namespaceName, CouchbaseClusterName+"-ui")
if err != nil {
return nil, errors.Wrap(err, "failed to get service")
}

var mgmtAddr string
var mgmtTlsAddr string
var connstr string
Expand All @@ -325,9 +370,22 @@ func (d *Deployer) GetConnectInfo(ctx context.Context, clusterID string) (*deplo
}
}

var connstrCb2 string

service, err = d.client.GetService(ctx, namespaceName, "cbdc2-"+CouchbaseClusterName+"-cng-service")
if err == nil {
for _, port := range service.Spec.Ports {
switch port.Name {
case "cloud-native-gateway-https":
connstrCb2 = fmt.Sprintf("couchbase2://%s:%d", externalIP, port.NodePort)
}
}
}

return &deployment.ConnectInfo{
ConnStr: connstr,
ConnStrTls: connstrTls,
ConnStrCb2: connstrCb2,
Mgmt: mgmtAddr,
MgmtTls: mgmtTlsAddr,
}, nil
Expand Down Expand Up @@ -395,6 +453,25 @@ func (d *Deployer) GetCertificate(ctx context.Context, clusterID string) (string
return "", errors.New("caodeploy does not support getting certificates")
}

func (d *Deployer) GetGatewayCertificate(ctx context.Context, clusterID string) (string, error) {
namespaceName, err := d.getClusterNamespace(ctx, clusterID)
if err != nil {
return "", err
}

secret, err := d.client.GetSecret(ctx, namespaceName, "couchbase-cloud-native-gateway-self-signed-secret-cluster")
if err != nil {
return "", errors.Wrap(err, "failed to get secret")
}

secretData := secret.Data["tls.crt"]
if len(secretData) == 0 {
return "", errors.New("secret data was unexpectedly empty")
}

return string(secretData), nil
}

func (d *Deployer) ExecuteQuery(ctx context.Context, clusterID string, query string) (string, error) {
return "", errors.New("caodeploy does not support executing queries")
}
Expand Down
4 changes: 4 additions & 0 deletions deployment/clouddeploy/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,10 @@ func (p *Deployer) GetCertificate(ctx context.Context, clusterID string) (string
return strings.TrimSpace(lastCert.Pem), nil
}

func (d *Deployer) GetGatewayCertificate(ctx context.Context, clusterID string) (string, error) {
return "", errors.New("clouddeploy does not support getting gateway certificates")
}

func (p *Deployer) ExecuteQuery(ctx context.Context, clusterID string, query string) (string, error) {
return "", errors.New("clouddeploy does not support executing queries")
}
Expand Down
2 changes: 2 additions & 0 deletions deployment/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type ClusterInfo interface {
type ConnectInfo struct {
ConnStr string
ConnStrTls string
ConnStrCb2 string
Mgmt string
MgmtTls string
}
Expand Down Expand Up @@ -91,6 +92,7 @@ type Deployer interface {
CreateBucket(ctx context.Context, clusterID string, opts *CreateBucketOptions) error
DeleteBucket(ctx context.Context, clusterID string, bucketName string) error
GetCertificate(ctx context.Context, clusterID string) (string, error)
GetGatewayCertificate(ctx context.Context, clusterID string) (string, error)
ExecuteQuery(ctx context.Context, clusterID string, query string) (string, error)
ListCollections(ctx context.Context, clusterID string, bucketName string) ([]ScopeInfo, error)
CreateScope(ctx context.Context, clusterID string, bucketName, scopeName string) error
Expand Down
4 changes: 4 additions & 0 deletions deployment/dockerdeploy/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,10 @@ func (d *Deployer) GetCertificate(ctx context.Context, clusterID string) (string
return strings.TrimSpace(lastCert.Pem), nil
}

func (d *Deployer) GetGatewayCertificate(ctx context.Context, clusterID string) (string, error) {
return "", errors.New("dockerdeploy does not support getting gateway certificates")
}

func (d *Deployer) ExecuteQuery(ctx context.Context, clusterID string, query string) (string, error) {
agent, err := d.getAgent(ctx, clusterID, "")
if err != nil {
Expand Down
Loading

0 comments on commit aed7a49

Please sign in to comment.