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
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,10 @@ docs:
generate-license: generate
go-licenses report --template .NOTICE.template ./... > NOTICE
copywrite headers apply

run-lima:
limactl start ./hack/lima-oms.yaml

stop-lima:
limactl stop lima-oms
limactl delete lima-oms
3 changes: 2 additions & 1 deletion cli/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type InstallCmd struct {
cmd *cobra.Command
}

func AddInstallCmd(rootCmd *cobra.Command) {
func AddInstallCmd(rootCmd *cobra.Command, opts *GlobalOptions) {
install := InstallCmd{
cmd: &cobra.Command{
Use: "install",
Expand All @@ -22,4 +22,5 @@ func AddInstallCmd(rootCmd *cobra.Command) {
},
}
rootCmd.AddCommand(install.cmd)
AddInstallCodesphereCmd(install.cmd, opts)
}
136 changes: 132 additions & 4 deletions cli/cmd/install_codesphere.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,150 @@
package cmd

import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"slices"

"github.com/codesphere-cloud/cs-go/pkg/io"
"github.com/codesphere-cloud/oms/internal/env"
"github.com/codesphere-cloud/oms/internal/installer"
"github.com/codesphere-cloud/oms/internal/util"
"github.com/spf13/cobra"
)

// InstallCodesphereCmd represents the codesphere command
type InstallCodesphereCmd struct {
cmd *cobra.Command
cmd *cobra.Command
Opts *InstallCodesphereOpts
Env env.Env
}

type InstallCodesphereOpts struct {
*GlobalOptions
Package string
Force bool
Config string
PrivKey string
SkipSteps []string
}

func (c *InstallCodesphereCmd) RunE(_ *cobra.Command, args []string) error {
workdir := c.Env.GetOmsWorkdir()
p := installer.NewPackage(workdir, c.Opts.Package)

err := c.ExtractAndInstall(p, runtime.GOOS, runtime.GOARCH)
if err != nil {
return fmt.Errorf("failed to extract and install package: %w", err)
}

return nil
}

func AddInstallCodesphereCmd(install *cobra.Command) {
func AddInstallCodesphereCmd(install *cobra.Command, opts *GlobalOptions) {
codesphere := InstallCodesphereCmd{
cmd: &cobra.Command{
Use: "codesphere",
Short: "Coming soon: Install a Codesphere instance",
Long: io.Long(`Coming soon: Install a Codesphere instance`),
Short: "Install a Codesphere instance",
Long: io.Long(`Install a Codesphere instance with the provided package, configuration file, and private key.
Uses the private-cloud-installer.js script included in the package to perform the installation.`),
},
Opts: &InstallCodesphereOpts{GlobalOptions: opts},
Env: env.NewEnv(),
}
codesphere.cmd.Flags().StringVarP(&codesphere.Opts.Package, "package", "p", "", "Package file (e.g. codesphere-v1.2.3-installer.tar.gz) to load binaries, installer etc. from")
codesphere.cmd.Flags().BoolVarP(&codesphere.Opts.Force, "force", "f", false, "Enforce package extraction")
codesphere.cmd.Flags().StringVarP(&codesphere.Opts.Config, "config", "c", "", "Path to the Codesphere Private Cloud configuration file (yaml)")
codesphere.cmd.Flags().StringVarP(&codesphere.Opts.PrivKey, "priv-key", "k", "", "Path to the private key to encrypt/decrypt secrets")
codesphere.cmd.Flags().StringSliceVarP(&codesphere.Opts.SkipSteps, "skip-steps", "s", []string{}, "Steps to be skipped. Must be one of: copy-dependencies, extract-dependencies, load-container-images, ceph, kubernetes")

util.MarkFlagRequired(codesphere.cmd, "package")
util.MarkFlagRequired(codesphere.cmd, "config")
util.MarkFlagRequired(codesphere.cmd, "priv-key")

install.AddCommand(codesphere.cmd)
codesphere.cmd.RunE = codesphere.RunE
}

func (c *InstallCodesphereCmd) ExtractAndInstall(p *installer.Package, goos string, goarch string) error {
if goos != "linux" || goarch != "amd64" {
return fmt.Errorf("codesphere installation is only supported on Linux amd64. Current platform: %s/%s", goos, goarch)
}

err := p.Extract(c.Opts.Force)
if err != nil {
return fmt.Errorf("failed to extract package to workdir: %w", err)
}

foundFiles, err := c.ListPackageContents(p)
if err != nil {
return fmt.Errorf("failed to list available files: %w", err)
}

if !slices.Contains(foundFiles, "deps.tar.gz") {
return fmt.Errorf("deps.tar.gz not found in package")
}
if !slices.Contains(foundFiles, "private-cloud-installer.js") {
return fmt.Errorf("private-cloud-installer.js not found in package")
}
if !slices.Contains(foundFiles, "node") {
return fmt.Errorf("node executable not found in package")
}

nodePath := filepath.Join(".", p.GetWorkDir(), "node")
err = os.Chmod(nodePath, 0755)
if err != nil {
return fmt.Errorf("failed to make node executable: %w", err)
}

log.Printf("Using Node.js executable: %s", nodePath)
log.Println("Starting private cloud installer script...")
installerPath := filepath.Join(".", p.GetWorkDir(), "private-cloud-installer.js")
archivePath := filepath.Join(".", p.GetWorkDir(), "deps.tar.gz")

// Build command
cmdArgs := []string{installerPath, "--archive", archivePath, "--config", c.Opts.Config, "--privKey", c.Opts.PrivKey}
if len(c.Opts.SkipSteps) > 0 {
for _, step := range c.Opts.SkipSteps {
cmdArgs = append(cmdArgs, "--skipStep", step)
}
}

cmd := exec.Command(nodePath, cmdArgs...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin

err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to run installer script: %w", err)
}
log.Println("Private cloud installer script finished.")

return nil
}

func (c *InstallCodesphereCmd) ListPackageContents(p *installer.Package) ([]string, error) {
packageDir := p.GetWorkDir()
if !p.FileIO.Exists(packageDir) {
return nil, fmt.Errorf("work dir not found: %s", packageDir)
}

entries, err := p.FileIO.ReadDir(packageDir)
if err != nil {
return nil, fmt.Errorf("failed to read directory contents: %w", err)
}

log.Printf("Listing contents of %s", packageDir)
var foundFiles []string
for _, entry := range entries {
filename := entry.Name()
log.Printf("- %s", filename)
foundFiles = append(foundFiles, filename)
}

return foundFiles, nil
}
Loading