Things about the CLI and the SaladCloud API that might surprise you. Command names such as create and delete below
are the saladcloud container-groups commands.
- Write warnings never show a secret. When
updateorscalereports what the API changed or ignored, an environment variable's value, a header's value or a credential field is named and described as(set),(changed),(removed)or(hidden), never printed, as--debug=bodyredacts them. deleteis immediate and unconfirmed. There is no prompt and no dry run, so it works unattended in scripts and agents. Confirm before you run it, and guard destructive automation in your own code.updateandscalewait for the change to settle before they return, so they can check the result against what you asked for and warn on stderr when the API changed or ignored part of it. A container change the platform rejected is an error instead: exit 6 with its reason, and the group keeps what it ran before.--no-waitreturns at once and skips the check.- The project falls back to
defaultwhen nothing sets one, and every command that uses it warns on stderr;whoamishows it asnone set, using "default". A saved project applies only to the saved organization. If the organization has nodefaultproject, commands exit 2 with "no valid project set". See Configuration. whoami'sauthenticatedistrue,false, ornull:truewhen the API accepted the key,falsewhen it rejected it, andnullwhen there was nothing to check (no key, or neither the list of your organizations nor an organization to check the key against). It is checked through that list, or the organization when the list is unavailable;organization_foundis the organization check,nullwhen it was not made.- The list of your organizations comes from an endpoint outside the documented API, so it may change or go
away without notice.
orgs listandorgs getread it, as do login's numbered list, the names in setup hints andwhoami'sorganizationsrow. When it is unavailable,loginasks you to type the organization's name instead of numbering them,login,useanddoctorcheck the organization you name directly (that check is in the documented API), hints say to runsaladcloud orgs listinstead of listing names, andwhoamishowsorganizationsasunknown(nullin JSON) and checks the key against the organization. Every other command works without it. - Empty table listings keep their header row on stdout, so
cut- orawk-style pipelines always see the same shape; a note on stderr says nothing matched.
- Deleted container group names are never released. Names are unique within an organization and project,
including against deleted groups, so re-using a name returns
name_conflict. Pick a new name. - A group created with autostart can come up
stopped, with no reason given. The create response sayspending, and about 20 seconds later the group readsstopped;container-groups start <group>starts it.create --waitreports it (kindgroup_stopped); a plaincreatereturns before it happens. - A new group can stay
pendingfor a long time while SaladCloud pulls its image, longer for a large image or when the platform is busy, with nothing logged yet; it then moves todeploying. If it stayspendingfor a very long time, contact SaladCloud support. - A group reads
runningonce any instance's container runs, ready or not. The group's counts don't include readiness, so a service whose readiness probe never passes still showsrunningingetandlist;instances listshows each instance's READY, and a wait forrunningprints a note when some aren't. The group's counts can also trailinstances listby a few seconds. - A large image can take a while to start on a node that has not pulled it before: instances sit in
Downloadingfor longer the bigger the image is. - The gateway can take a short while to start routing to a new instance. Right after an instance first reads ready, requests to the group's URL can get 503 for a minute or so.
- Changing the image, command, environment, probes or gateway settings restarts every instance onto the new version as its node next checks in; old and new never run side by side. For no downtime, run the new version as a second group (see Updating with flags).
- A container change is checked after the API accepts it. The patch returns 200 and the change waits as a new
version (
Version 2 is pending.); a version whose image the registry does not serve is then dropped, the group keeps running the one it had, and its reason readsVersion 2: Manifest Not Found. That reason stays on the group through later writes until a new version replaces it.updateexits 6 with the reason. - A new private image needs its registry credentials again.
update --imagewith a new tag of a private Docker Hub image, sent withoutcontainer.registry_authentication, is rejected withImage Not Found, Check Image Name And Tag, even though the group was created with credentials for that repository. Send the credentials with the new image in the-ffile; the CLI cannot resend them, because the API never returns them. The rejection's hint says so for an image on any registry. - Setting
replicasputs scheduled scaling on hold, whether throughscale,update, or the portal. The CLI says so when it happens;scale --keep-scheduleswitches the schedule back on. See Scheduled scaling. - A running or deploying GPU group can lower its priority only after 60 minutes at its current one. Until then,
update --prioritywith a lower tier fails with exit 6 (kindinvalid_input) and the API's message saying so. A stopped group's priority changes at once, so to lower it now,stopthe group,update --priority, thenstartit. - Job queues (see Job queues):
createacceptsqueue_autoscalerand drops it: the group comes back withqueue_autoscaler: null, andcreatewarns on stderr. Set it withcontainer-groups update -fonce the group exists.- Setting
queue_autoscaleralso changesreplicas(1 to 0 withmin_replicas0);updatewarns. queues getlists no container groups:container_groupsis[]even while a connected group is running, so the GROUPS column ofqueues listshows-for an empty list.- Canceling a running job marks it
cancelledand discards its output, but the instance still runs it to the end. - A stopped or deleted group's worker can take new jobs for some seconds afterwards. Such a job, like one whose
instance was interrupted, reads
runninguntil its lease runs out (about 5.5 minutes) and a worker next asks for work; with no worker left on the queue, it staysrunning. - Deleting a queue deletes its pending jobs and removes the connection from every group connected to it, for good; a new queue of the same name does not reconnect them.
- A reply over 10 MB counts as a failed attempt, so the job runs four times and then fails with no reason given.
- The job queue worker logs only errors by default, so a failed attempt leaves no line in the logs. Its
README names the
environment variable that raises the level; at
infoit logs each job, full input included.
- An invalid
container.commandnever settles. The instance fails at start and the platform moves it to another node, over and over: the group never reachesrunning, each attempt's logs stop after "Instance Starting", and--waittimes out. A common cause is busybox'ssleep, which takes a number of seconds, notinfinity; the examples usesleep 2147483647. The platform also drops empty words fromcontainer.commandand trims the spaces around each word, socreate/update -- <command>refuses an empty word. - SSH has a few relay rules. Each account registers exactly one public key (ssh-ed25519 or ssh-rsa) in the portal,
at https://portal.salad.com/ssh-keys, and registering one replaces any other;
saladcloud ssh-key setupfinds or generates a local key and prints it with that link. A one-shotcontainer-groups ssh <group> -- <cmd>will exit 1 even when the command succeeded, because the relay does not pass exit codes back (the CLI prints a note;cp,sftpand interactive sessions are unaffected). Its output also comes through a terminal, so stderr is mixed into stdout and programs may add color; move files withcp. An instance can readrunninga minute or so before the platform assigns its SSH endpoint (the SSH column ofinstances list); until thensshsays so.--usermust exist in the image;rootalways works. Shell syntax such as&&works in one-shot commands. The CLI keeps relay host keys in its ownknown_hostsbeside the config file, filed under each instance's ID rather than the relay's address, so a relay port another instance reused neither conflicts with your~/.ssh/known_hostsnor fails the host-key check. cp -rfollows sftp's directory rule. When the destination directory already exists the source is copied inside it (cp -r ./input my-app:/datamakes/data/input); when it does not, it is created as the copy. End a remote path with/.to download only its contents (cp -r my-app:/outputs/. ./results).logs --followcan miss entries that arrive very late. The API can only search by when an entry was emitted, not when it was stored, so--followreads behind itself: each poll re-reads the 10 seconds before the previous poll, and once a minute a settle scan reads the minute that has just aged past--lookback(default 2m). An entry that arrives up to--lookbacklate is printed, about--lookbackafter the rest; one that arrives later is missed. Raise--lookbackfor workloads whose logs reach SaladCloud with a long delay. An entry that a node with a fast clock stamps ahead of this machine's clock is printed once this clock reaches its time.logs --followcan fall behind a group that logs fast. A log request returns at most 100 entries and takes about a second, so one reader gets about 100 entries a second. When a poll takes longer than--poll-interval,--followskips the settle scan (and says so once) to keep up with new entries, so very late entries may be missed; above about 100 entries a second it falls further behind.- Log time ranges have millisecond precision. Finer
--since/--untilvalues are rounded outward automatically. - GPU availability can read 0 when the availability service is overloaded: it then answers with every count at 0
instead of an error, so an overloaded class looks like an empty one. The on-call count (
on_call_gpu,on_call_cpuin JSON) is 0 for every row today and is no tell; the table leaves itsON-CALLcolumn out until a row reports one.availabilityprints a stderrwarning:for each row whose every priority-tier count is 0. Treat those counts as unknown and runavailabilityagain. - One availability query for several GPU classes is its own answer, not the sum of the per-class queries. It is
taken separately, so it neither equals nor bounds their sum: a node that carries more than one of the classes counts
once in it, and the counts move between queries.
availabilityshows one row per class plus the combined query's own answer, never a total of the rows. - The availability service sometimes answers all zeros between two good answers.
availabilityasks once more when every count is zero; a row still all zeros gets the stderr warning marking it unknown. - Some responses carry
restart_policyorpriorityas a number instead of its name: 1, 2, 3 foralways,on_failure,never, and 1 to 4 forhigh,medium,low,batch. The CLI rewrites a known number to its name and drops one with no name (such as 0), so that field readsnullrather than failing the whole command. - Queue job listings page at 25. The API rejects
page_sizeabove 25 for queue jobs (the API reference allows 100), as it does for inference endpoints and jobs. - Job listings come in no useful order and with no total. Inference jobs are listed oldest first and queue jobs in
job ID order, with no sort option and a null
total_size. The CLI shows both newest first: it searches for the last page of an inference listing and reads backwards. A queue listing has to be read and sorted; with a--limit(100 by default)queues jobs listreads at most 1,000 jobs (or the limit, if larger), and says on stderr when the queue may hold more than it read, since the newest are then the newest of those read.--limit 0reads every job, up to 10,000, which takes a while on a long queue.