1050 lines
22 KiB
Go
1050 lines
22 KiB
Go
package command
|
|
|
|
import (
|
|
"cryosparc-merlin/ui"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"charm.land/huh/v2"
|
|
)
|
|
|
|
// =============================================================================
|
|
// cryosparcm commands Steps
|
|
// =============================================================================
|
|
func (i *Command) CryosparcmStep(
|
|
hostname,
|
|
cryosparcpath string,
|
|
help bool,
|
|
args ...string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: strings.TrimSpace(
|
|
fmt.Sprintf("Running cryosparcm %s", strings.Join(args, " "))) +
|
|
fmt.Sprintf(" (instance: %s)", cryosparcpath),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
return cryosparcmCmd(hostname, cryosparcpath, "", help, args...)
|
|
},
|
|
}
|
|
}
|
|
|
|
func (i *Command) CryosparcmStartStep(
|
|
hostname,
|
|
cryosparcpath string,
|
|
help bool) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Starting CryoSPARC (instance: %s)", cryosparcpath),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
return cryosparcmCmd(hostname, cryosparcpath, "", help, "start")
|
|
},
|
|
}
|
|
}
|
|
|
|
func (i *Command) CryosparcmStopStep(
|
|
hostname,
|
|
cryosparcpath string,
|
|
help bool) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Stopping CryoSPARC (instance: %s)", cryosparcpath),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
return cryosparcmCmd(hostname, cryosparcpath, "", help, "stop")
|
|
},
|
|
}
|
|
}
|
|
|
|
func (i *Command) CryosparcmCreateUserStep(
|
|
hostname,
|
|
cryosparcpath,
|
|
email,
|
|
username,
|
|
firstname,
|
|
lastname string,
|
|
help bool) ui.Step {
|
|
|
|
var password string
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Creating CryoSPARC user (instance: %s)", cryosparcpath),
|
|
CompletedMessage: nil,
|
|
Condition: func() (bool, error) {
|
|
return true, nil
|
|
},
|
|
Prompt: func() *huh.Form {
|
|
return huh.NewForm(
|
|
huh.NewGroup(
|
|
huh.NewNote().
|
|
Title("Create CryoSPARC user"),
|
|
|
|
huh.NewInput().
|
|
Title("Email").
|
|
Validate(func(s string) error {
|
|
if s == "" {
|
|
return errors.New("email is required")
|
|
}
|
|
return nil
|
|
}).
|
|
Value(&email),
|
|
|
|
huh.NewInput().
|
|
Title("Password (different from your PSI password)").
|
|
EchoMode(huh.EchoModePassword).
|
|
Validate(func(s string) error {
|
|
if s == "" {
|
|
return errors.New("password is required")
|
|
}
|
|
return nil
|
|
}).
|
|
Value(&password),
|
|
|
|
huh.NewInput().
|
|
Title("Username").
|
|
Value(&username),
|
|
|
|
huh.NewInput().
|
|
Title("First Name").
|
|
Value(&firstname),
|
|
|
|
huh.NewInput().
|
|
Title("Last Name").
|
|
Value(&lastname),
|
|
),
|
|
)
|
|
},
|
|
Exec: func() *exec.Cmd {
|
|
|
|
var args []string
|
|
|
|
versionData, err := os.ReadFile(
|
|
filepath.Join(cryosparcpath, "cryosparc_master", "version"))
|
|
|
|
if err == nil {
|
|
version := strings.TrimSpace(string(versionData))
|
|
version = strings.TrimPrefix(version, "v")
|
|
|
|
major, _, ok := strings.Cut(version, ".")
|
|
if !ok {
|
|
major = version
|
|
}
|
|
|
|
if majorVersion, err := strconv.Atoi(major); err == nil &&
|
|
majorVersion >= 5 {
|
|
args = append(args, "user", "create")
|
|
} else {
|
|
args = append(args, "createuser")
|
|
}
|
|
} else {
|
|
args = append(args, "createuser")
|
|
}
|
|
|
|
args = append(args,
|
|
"--email", email,
|
|
"--password", password,
|
|
"--username", username,
|
|
"--firstname", firstname,
|
|
"--lastname", lastname)
|
|
|
|
return cryosparcmCmd(
|
|
hostname,
|
|
cryosparcpath,
|
|
"",
|
|
help,
|
|
args...)
|
|
},
|
|
}
|
|
}
|
|
|
|
func (i *Command) CryosparcmChangePortStep(
|
|
hostname,
|
|
cryosparcpath string,
|
|
port, start, end, count uint,
|
|
help bool) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Changing base port (instance: %s)", cryosparcpath),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
|
|
if port == 0 {
|
|
_ = i.setCryosparcBasePort(hostname, start, end, count)
|
|
}
|
|
|
|
return cryosparcmCmd(
|
|
hostname,
|
|
cryosparcpath,
|
|
"",
|
|
help,
|
|
"changeport",
|
|
strconv.FormatUint(uint64(i.cfg.BasePort), 10),
|
|
)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// cryosparcm commands Steps
|
|
// =============================================================================
|
|
func (i *Command) CryosparcwStep(
|
|
cryosparcpath string,
|
|
arch string,
|
|
help bool,
|
|
args ...string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: strings.TrimSpace(
|
|
fmt.Sprintf("Running cryosparcw %s", strings.Join(args, " "))) +
|
|
fmt.Sprintf(" (instance: %s)", cryosparcpath),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
return cryosparcwCmd(cryosparcpath, arch, help, args...)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Check Install Directory
|
|
// =============================================================================
|
|
func (i *Command) checkInstallDirStep(oldDir, newDir string) ui.Step {
|
|
var action string
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Preparing installation directory %s", oldDir),
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"Created installation directory %s", newDir)
|
|
},
|
|
Condition: func() (bool, error) {
|
|
return directoryExistsAndNotEmpty(oldDir)
|
|
},
|
|
Prompt: func() *huh.Form {
|
|
return huh.NewForm(
|
|
huh.NewGroup(
|
|
huh.NewSelect[string]().
|
|
Title(fmt.Sprintf(
|
|
"%q already exists",
|
|
oldDir,
|
|
)).
|
|
Options(
|
|
huh.NewOption("Overwrite directory", "overwrite"),
|
|
huh.NewOption("Cancel installation", "cancel"),
|
|
).
|
|
Value(&action),
|
|
),
|
|
)
|
|
},
|
|
Action: func(update func(float64)) error {
|
|
switch action {
|
|
|
|
case "cancel":
|
|
return ErrCancelled
|
|
|
|
case "overwrite":
|
|
|
|
if err := os.RemoveAll(oldDir); err != nil {
|
|
return err
|
|
}
|
|
|
|
return i.createDirectory(update, newDir)
|
|
|
|
default:
|
|
return i.createDirectory(update, newDir)
|
|
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Backup CryoSPARC database
|
|
// =============================================================================
|
|
func (i *Command) backupCryosparcDatabaseStep(
|
|
cryosparcpath,
|
|
dbpath,
|
|
backupdir string) ui.Step {
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Backing up CryoSPARC database (%s)", dbpath),
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"Backed up CryoSPARC database (destination: %s)", backupdir)
|
|
},
|
|
Skip: func() bool {
|
|
exists, _ := directoryExistsAndNotEmpty(dbpath)
|
|
return !exists
|
|
},
|
|
SkipMessage: fmt.Sprintf(
|
|
"Database backup skipped: "+
|
|
"Previous database is empty or does not exist (%s)",
|
|
dbpath),
|
|
Action: func(update func(float64)) error {
|
|
return i.backupCryosparcDatabase(
|
|
update,
|
|
cryosparcpath,
|
|
dbpath,
|
|
backupdir)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Create DbPath Step
|
|
// =============================================================================
|
|
func (i *Command) createDbPathStep(dbpath string) ui.Step {
|
|
var action string
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Creating database directory %s", dbpath),
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"Created database directory %s", dbpath)
|
|
},
|
|
Condition: func() (bool, error) {
|
|
|
|
return directoryExistsAndNotEmpty(dbpath)
|
|
},
|
|
Prompt: func() *huh.Form {
|
|
return huh.NewForm(
|
|
huh.NewGroup(
|
|
huh.NewSelect[string]().
|
|
Title(fmt.Sprintf(
|
|
"%q already exists",
|
|
dbpath,
|
|
)).
|
|
Options(
|
|
huh.NewOption("Overwrite database", "overwrite"),
|
|
huh.NewOption("Cancel installation", "cancel"),
|
|
).
|
|
Value(&action),
|
|
),
|
|
)
|
|
},
|
|
Action: func(update func(float64)) error {
|
|
switch action {
|
|
case "cancel":
|
|
return ErrCancelled
|
|
|
|
case "overwrite":
|
|
if err := os.RemoveAll(dbpath); err != nil {
|
|
return err
|
|
}
|
|
return i.createDirectory(update, dbpath)
|
|
|
|
default:
|
|
return i.createDirectory(update, dbpath)
|
|
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Download CryoSPARC Step
|
|
// =============================================================================
|
|
var newDownloadDir string
|
|
|
|
func (i *Command) downloadCryosparcStep(
|
|
downloaddir,
|
|
release,
|
|
license,
|
|
installation,
|
|
arch string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Downloading CryoSPARC %s v%s arch=%s",
|
|
installation, release, arch),
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"Downloaded CryoSPARC %s v%s arch=%s",
|
|
installation, release, arch)
|
|
},
|
|
Skip: func() bool {
|
|
|
|
basePath := fmt.Sprintf(
|
|
"/data/project/cls/shared/software/cryosparc/installations/v%s/%s",
|
|
release,
|
|
arch,
|
|
)
|
|
|
|
path := filepath.Join(basePath, fmt.Sprintf(
|
|
"cryosparc_%s.tar.gz",
|
|
installation,
|
|
))
|
|
|
|
_, err := os.Stat(path)
|
|
|
|
if err == nil {
|
|
newDownloadDir = basePath
|
|
return true
|
|
}
|
|
return false
|
|
|
|
},
|
|
SkipMessage: fmt.Sprintf(
|
|
"CryoSPARC %s v%s arch=%s was already downloaded",
|
|
installation,
|
|
release,
|
|
arch),
|
|
ShowProgressBar: true,
|
|
Action: func(update func(float64)) error {
|
|
|
|
return i.downloadCryosparc(
|
|
update,
|
|
downloaddir,
|
|
release,
|
|
license,
|
|
installation,
|
|
arch)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Extract Archive Step
|
|
// =============================================================================
|
|
func (i *Command) ExtractArchiveStep(
|
|
extractdir,
|
|
release,
|
|
installation,
|
|
arch string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Extracting CryoSPARC %s v%s arch=%s", installation, release, arch),
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"Extracted CryoSPARC %s v%s arch=%s", installation, release, arch)
|
|
},
|
|
Action: func(update func(float64)) error {
|
|
|
|
var downloaddir string
|
|
|
|
if newDownloadDir != "" {
|
|
downloaddir = newDownloadDir
|
|
} else {
|
|
downloaddir = extractdir
|
|
}
|
|
|
|
return i.extractArchive(
|
|
update,
|
|
downloaddir,
|
|
extractdir,
|
|
fmt.Sprintf("cryosparc_%s.tar.gz", installation))
|
|
},
|
|
}
|
|
}
|
|
|
|
func (i *Command) RenameWorkerDirectoryStep(
|
|
cryosparcpath,
|
|
arch string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: "Renaming worker directory",
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf("Directory renamed to: %s",
|
|
filepath.Join(cryosparcpath,
|
|
fmt.Sprintf("cryosparc_worker_%s", arch)))
|
|
},
|
|
Action: func(update func(float64)) error {
|
|
return i.renameDirectory(
|
|
filepath.Join(cryosparcpath, "cryosparc_worker"),
|
|
filepath.Join(cryosparcpath,
|
|
fmt.Sprintf("cryosparc_worker_%s", arch)),
|
|
)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Install Master Step
|
|
// =============================================================================
|
|
func (i *Command) InstallMasterStep(
|
|
cryosparcpath,
|
|
release,
|
|
license,
|
|
hostname,
|
|
dbpath,
|
|
ssdpath,
|
|
arch string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Installing CryoSPARC master v%s arch=%s", release, arch),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
|
|
return i.installMaster(
|
|
cryosparcpath,
|
|
license,
|
|
hostname,
|
|
dbpath,
|
|
ssdpath,
|
|
arch,
|
|
i.cfg.BasePort)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Install Worker Step
|
|
// =============================================================================
|
|
func (i *Command) InstallWorkerStep(
|
|
cryosparcpath,
|
|
release,
|
|
license,
|
|
arch string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Installing CryoSPARC worker v%s arch=%s", release, arch),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
|
|
return i.installWorker(
|
|
cryosparcpath,
|
|
license,
|
|
arch)
|
|
},
|
|
}
|
|
|
|
}
|
|
|
|
// =============================================================================
|
|
// Replace license ID in config.sh Step
|
|
// =============================================================================
|
|
func (i *Command) replaceLicenseIDStep(
|
|
installDir,
|
|
license,
|
|
installation string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf(
|
|
"Checking CryoSPARC %s License ID", installation),
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"Checked CryoSPARC %s License ID", installation)
|
|
},
|
|
Action: func(update func(float64)) error {
|
|
return i.replaceLicenseID(update, installDir, license)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Lanes Steps (single lanes)
|
|
// =============================================================================
|
|
|
|
// create
|
|
func (i *Command) LanesCreateStep(
|
|
cryosparcpath,
|
|
name,
|
|
cachepath,
|
|
memory,
|
|
time,
|
|
partition,
|
|
gpus,
|
|
cpuspertask,
|
|
cluster,
|
|
arch string) ui.Step {
|
|
|
|
var action string
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf("Creating CryoSPARC lane: '%s' (%s)",
|
|
name,
|
|
filepath.Join(cryosparcpath, "lanes", name),
|
|
),
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf("Created CryoSPARC lane: '%s' (%s)",
|
|
name,
|
|
filepath.Join(cryosparcpath, "lanes", name),
|
|
)
|
|
},
|
|
Condition: func() (bool, error) {
|
|
return directoryExistsAndNotEmpty(
|
|
filepath.Join(cryosparcpath, "lanes", name))
|
|
},
|
|
Prompt: func() *huh.Form {
|
|
return huh.NewForm(
|
|
huh.NewGroup(
|
|
huh.NewSelect[string]().
|
|
Title(fmt.Sprintf(
|
|
"%q already exists",
|
|
filepath.Join(cryosparcpath, "lanes", name),
|
|
)).
|
|
Options(
|
|
huh.NewOption("Overwrite lane", "overwrite"),
|
|
huh.NewOption("Skip lane", "skip"),
|
|
).
|
|
Value(&action),
|
|
),
|
|
)
|
|
},
|
|
Skip: func() bool {
|
|
return action == "skip"
|
|
},
|
|
SkipMessage: fmt.Sprintf(
|
|
"Skipped creating lane %s",
|
|
filepath.Join(cryosparcpath, "lanes", name)),
|
|
Action: func(update func(float64)) error {
|
|
return i.CreateLane(
|
|
update,
|
|
cryosparcpath,
|
|
name,
|
|
cachepath,
|
|
memory,
|
|
time,
|
|
partition,
|
|
gpus,
|
|
cpuspertask,
|
|
cluster,
|
|
arch)
|
|
},
|
|
}
|
|
}
|
|
|
|
// install
|
|
func (i *Command) LanesInstallStep(
|
|
hostname,
|
|
cryosparcpath,
|
|
lanepath,
|
|
info,
|
|
script string,
|
|
help bool) ui.Step {
|
|
return ui.Step{
|
|
Message: fmt.Sprintf("Installing CryoSPARC lane (instance: %s)",
|
|
cryosparcpath,
|
|
),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
|
|
cmdArgs := append([]string{"cluster", "connect"},
|
|
"--info", info,
|
|
"--script", script,
|
|
)
|
|
|
|
return cryosparcmCmd(
|
|
hostname,
|
|
cryosparcpath,
|
|
lanepath,
|
|
help,
|
|
cmdArgs...,
|
|
)
|
|
|
|
},
|
|
}
|
|
}
|
|
|
|
// remove
|
|
func (i *Command) LanesRemoveStep(
|
|
hostname,
|
|
cryosparcpath,
|
|
name string,
|
|
help bool) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: fmt.Sprintf("Removing CryoSPARC lane from database (%s)",
|
|
name,
|
|
),
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
|
|
cmdArgs := append([]string{"cluster", "remove"}, name)
|
|
|
|
return cryosparcmCmd(hostname, cryosparcpath, "", help, cmdArgs...)
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Lanes Steps (multiple lanes)
|
|
// =============================================================================
|
|
|
|
// create default
|
|
|
|
// LanesCreateDefaultSteps creates the default lanes created to run CryoSPARC
|
|
// in the Merlin cluster
|
|
func (i *Command) LanesCreateDefaultSteps(
|
|
cryosparcpath,
|
|
cachepath,
|
|
memory,
|
|
gpus,
|
|
cpuspertask,
|
|
arch string) []ui.Step {
|
|
|
|
steps := make(map[string]ui.Step)
|
|
|
|
if arch == "aarch64" {
|
|
|
|
steps["gh-hourly"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"gh-hourly",
|
|
cachepath,
|
|
memory,
|
|
"00-01:00:00",
|
|
"gh-hourly",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["gh-daily"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"gh-daily",
|
|
cachepath,
|
|
memory,
|
|
"01-00:00:00",
|
|
"gh-daily",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["gh-daily-4h"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"gh-daily-4h",
|
|
cachepath,
|
|
memory,
|
|
"00-04:00:00",
|
|
"gh-daily",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["gh-general-2d"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"gh-general-2d",
|
|
cachepath,
|
|
memory,
|
|
"02-00:00:00",
|
|
"gh-general",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["gh-general-2d-100Gb"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"gh-general-2d-100Gb",
|
|
cachepath,
|
|
"100",
|
|
"02-00:00:00",
|
|
"gh-general",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
} else {
|
|
steps["cpu-hourly"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"cpu-hourly",
|
|
cachepath,
|
|
memory,
|
|
"00-01:00:00",
|
|
"hourly",
|
|
gpus,
|
|
cpuspertask,
|
|
"merlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["cpu-daily"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"cpu-daily",
|
|
cachepath,
|
|
memory,
|
|
"01-00:00:00",
|
|
"daily",
|
|
gpus,
|
|
cpuspertask,
|
|
"merlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["a100-hourly"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"a100-hourly",
|
|
cachepath,
|
|
memory,
|
|
"00-01:00:00",
|
|
"a100-hourly",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["a100-daily"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"a100-daily",
|
|
cachepath,
|
|
memory,
|
|
"01-00:00:00",
|
|
"a100-daily",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["a100-daily-4h"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"a100-daily-4h",
|
|
cachepath,
|
|
memory,
|
|
"00-04:00:00",
|
|
"a100-daily",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["a100-general-2d"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"a100-general-2d",
|
|
cachepath,
|
|
memory,
|
|
"02-00:00:00",
|
|
"a100-general",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
steps["a100-general-2d-100Gb"] = i.LanesCreateStep(
|
|
cryosparcpath,
|
|
"a100-general-2d-100Gb",
|
|
cachepath,
|
|
"100",
|
|
"02-00:00:00",
|
|
"a100-general",
|
|
gpus,
|
|
cpuspertask,
|
|
"gmerlin7",
|
|
arch,
|
|
)
|
|
|
|
}
|
|
|
|
keys := make([]string, 0, len(steps))
|
|
for key := range steps {
|
|
keys = append(keys, key)
|
|
}
|
|
|
|
stepsList := make([]ui.Step, 0, len(steps)+1)
|
|
stepsList = append(
|
|
stepsList,
|
|
i.LanesCreateDefaultConfirmStep(cryosparcpath, keys),
|
|
)
|
|
|
|
for key := range steps {
|
|
stepsList = append(stepsList, steps[key])
|
|
}
|
|
|
|
return stepsList
|
|
}
|
|
|
|
// create default (confirm step)
|
|
|
|
// LanesCreateDefaultConfirmStep is used to confirm if the creation of all
|
|
// default lanes into cryosparc path can proceed.
|
|
func (i *Command) LanesCreateDefaultConfirmStep(
|
|
cryosparcPath string,
|
|
stepNames []string,
|
|
) ui.Step {
|
|
var proceed bool
|
|
|
|
return ui.Step{
|
|
Message: "Creating all default lanes",
|
|
CompletedMessage: nil,
|
|
Condition: func() (bool, error) {
|
|
return true, nil
|
|
},
|
|
Prompt: func() *huh.Form {
|
|
return huh.NewForm(
|
|
huh.NewGroup(
|
|
huh.NewConfirm().
|
|
Title(fmt.Sprintf(
|
|
"This will create all default lanes "+
|
|
"in %s:\n\n%s\n\nDo you want to proceed?",
|
|
filepath.Join(cryosparcPath, "lanes"),
|
|
strings.Join(stepNames, "\n"),
|
|
)).
|
|
Affirmative("Confirm").
|
|
Negative("Cancel").
|
|
Value(&proceed),
|
|
),
|
|
)
|
|
},
|
|
Action: func(update func(float64)) error {
|
|
if !proceed {
|
|
return ErrCancelled
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
// install
|
|
|
|
// LanesInstallSteps combines the installation of multiple lanes using the
|
|
// previously defined single lane install (RunLanesInstallStep).
|
|
func (i *Command) LanesInstallSteps(
|
|
hostname,
|
|
cryosparcpath,
|
|
info,
|
|
script,
|
|
name string,
|
|
all,
|
|
help bool) []ui.Step {
|
|
|
|
var lanes []string
|
|
|
|
steps := make([]ui.Step, 0)
|
|
|
|
if info == "" && script == "" {
|
|
|
|
if name != "" {
|
|
|
|
lanes = append(lanes, filepath.Join(cryosparcpath, "lanes", name))
|
|
|
|
} else if all {
|
|
|
|
var err error
|
|
lanes, err = filepath.Glob(
|
|
filepath.Join(cryosparcpath, "lanes", "*"),
|
|
)
|
|
if err != nil {
|
|
fmt.Printf("Error: %s", err)
|
|
return nil
|
|
}
|
|
|
|
} else {
|
|
fmt.Println("no lanes selected. Use '--name <lane name>' " +
|
|
"to select a lane to install or '--all' to install all " +
|
|
"lanes stored in the CryoSPARC directory.")
|
|
return nil
|
|
}
|
|
|
|
for _, lanepath := range lanes {
|
|
|
|
info = filepath.Join(lanepath, "cluster_info.json")
|
|
script = filepath.Join(lanepath, "cluster_script.sh")
|
|
|
|
steps = append(steps,
|
|
i.LanesInstallStep(
|
|
hostname,
|
|
cryosparcpath,
|
|
lanepath,
|
|
info,
|
|
script,
|
|
help,
|
|
),
|
|
)
|
|
}
|
|
|
|
} else {
|
|
steps = append(steps,
|
|
i.LanesInstallStep(
|
|
hostname,
|
|
cryosparcpath,
|
|
"",
|
|
info,
|
|
script,
|
|
help,
|
|
),
|
|
)
|
|
}
|
|
|
|
return steps
|
|
}
|
|
|
|
// =============================================================================
|
|
// HTTP link
|
|
// =============================================================================
|
|
func (i *Command) HttpUrlStep(hostname string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: "",
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"CryoSPARC instance can be accessed on: http://%s:%d",
|
|
hostname,
|
|
i.cfg.BasePort,
|
|
)
|
|
},
|
|
Action: func(update func(float64)) error {
|
|
return nil
|
|
},
|
|
}
|
|
|
|
}
|
|
|
|
// =============================================================================
|
|
// Set CryoSPARC base port
|
|
// =============================================================================
|
|
func (i *Command) setCryosparcBasePortStep(
|
|
hostname string,
|
|
port, start, end, count uint) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: "Setting CryoSPARC base port",
|
|
CompletedMessage: func() string {
|
|
return fmt.Sprintf(
|
|
"Set CryoSPARC base port to %d",
|
|
i.cfg.BasePort,
|
|
)
|
|
},
|
|
Skip: func() bool {
|
|
return port != 0
|
|
},
|
|
SkipMessage: fmt.Sprintf(
|
|
"CryoSPARC base port was already provided and set to %d", port),
|
|
Action: func(update func(float64)) error {
|
|
|
|
return i.setCryosparcBasePort(hostname, start, end, count)
|
|
|
|
},
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Check running instances
|
|
// =============================================================================
|
|
func (i *Command) CheckInstancesStep(hostname string) ui.Step {
|
|
|
|
return ui.Step{
|
|
Message: "Checking running CryoSPARC instances",
|
|
CompletedMessage: nil,
|
|
Exec: func() *exec.Cmd {
|
|
|
|
return i.checkInstances(hostname)
|
|
|
|
},
|
|
}
|
|
}
|