-
Notifications
You must be signed in to change notification settings - Fork 17
/
Spacefile.sh
1390 lines (1135 loc) · 48.6 KB
/
Spacefile.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
##
# Public entry point functions for command line and for direct space invocation.
# Functions here are wrappers to other functions.
CLUSTER_CREATE()
{
SPACE_SIGNATURE="clusterName"
SPACE_DEP="_PRJ_CLUSTER_CREATE"
local clusterName="${1}"
shift
_PRJ_CLUSTER_CREATE "${PWD}" "${clusterName}"
}
CLUSTER_SYNC()
{
SPACE_SIGNATURE="forceSync:0 quite:0 [podToOverwrite]"
SPACE_DEP="_SYNC_RUN"
_SYNC_RUN "$@"
}
HOST_CREATE()
{
SPACE_SIGNATURE="host [jumphost expose hostHome hostAddress user userKey superUser superUserKey internal routerAddress]"
SPACE_DEP="_PRJ_HOST_CREATE"
local host="${1}"
shift
local jumpHost="${1:-}"
shift $(($# > 0 ? 1 : 0))
local expose="${1:-}"
shift $(($# > 0 ? 1 : 0))
local hostHome="${1:-}"
shift $(($# > 0 ? 1 : 0))
local hostAddress="${1:-}"
shift $(($# > 0 ? 1 : 0))
local user="${1:-}"
shift $(($# > 0 ? 1 : 0))
local userKey="${1:-}"
shift $(($# > 0 ? 1 : 0))
local superUser="${1:-}"
shift $(($# > 0 ? 1 : 0))
local superUserKey="${1:-}"
shift $(($# > 0 ? 1 : 0))
local internal="${1:-}"
shift $(($# > 0 ? 1 : 0))
local routerAddress="${1:-}"
shift $(($# > 0 ? 1 : 0))
_PRJ_HOST_CREATE "${host}" "${jumpHost}" "${expose}" "${hostHome}" "${hostAddress}" "${user}" "${userKey}" "${superUser}" "${superUserKey}" "${internal}" "${routerAddress}"
}
HOST_INIT()
{
SPACE_SIGNATURE="host [force]"
SPACE_DEP="_PRJ_HOST_INIT"
local host="${1}"
shift
local force="${1:-false}"
shift $(($# > 0 ? 1 : 0))
_PRJ_HOST_INIT "${host}" "${force}"
}
HOST_DISABLE_ROOT()
{
SPACE_SIGNATURE="host"
SPACE_DEP="_PRJ_HOST_DISABLE_ROOT"
local host="${1}"
shift
_PRJ_HOST_DISABLE_ROOT "${host}"
}
# Looging in as root, create a new super user on the host.
HOST_CREATE_SUPERUSER()
{
SPACE_SIGNATURE="host keyfile:0 [superuser superkeyfile]"
SPACE_DEP="_PRJ_HOST_CREATE_SUPERUSER"
_PRJ_HOST_CREATE_SUPERUSER "$@"
}
REGISTRY_CONFIG()
{
SPACE_SIGNATURE="[host]"
SPACE_DEP="_PRJ_REGISTRY_CONFIG"
local host="${1:-}"
shift $(($# > 0 ? 1 : 0))
_PRJ_REGISTRY_CONFIG "${host}"
}
# Run as superuser
HOST_SETUP()
{
SPACE_SIGNATURE="host strictUserKeys:0 strictSuperUserKeys:0 [skipFirewall skipSystemd skipPodman]"
SPACE_DEP="_PRJ_HOST_SETUP"
_PRJ_HOST_SETUP "$@"
}
CLUSTER_STATUS()
{
SPACE_DEP="_PRJ_GET_CLUSTER_STATUS"
_PRJ_GET_CLUSTER_STATUS
}
LIST_HOSTS()
{
SPACE_SIGNATURE="[all showState pod]"
SPACE_DEP="_PRJ_LIST_HOSTS"
local all="${1:-false}"
shift $(($# > 0 ? 1 : 0))
local showState="${1:-false}"
shift $(($# > 0 ? 1 : 0))
local pod="${1:-}"
shift $(($# > 0 ? 1 : 0))
local filter="1"
if [ "${all}" = "true" ]; then
filter="0"
fi
_PRJ_LIST_HOSTS "${filter}" "${showState}" "${pod}"
}
ATTACH_POD()
{
SPACE_SIGNATURE="podTuple [gitUrl]"
SPACE_DEP="_PRJ_ATTACH_POD"
local podTuple="${1}"
shift
local gitUrl="${1:-}"
_PRJ_ATTACH_POD "${podTuple}" "${gitUrl}"
}
DETACH_POD()
{
SPACE_SIGNATURE="podTuple"
SPACE_DEP="_PRJ_DETACH_POD"
local podTuple="${1}"
shift
_PRJ_DETACH_POD "${podTuple}"
}
CLUSTER_IMPORT_POD_CFG()
{
SPACE_SIGNATURE="pod"
SPACE_DEP="_PRJ_CLUSTER_IMPORT_POD_CFG"
local pod="${1}"
shift
_PRJ_CLUSTER_IMPORT_POD_CFG "${pod}"
}
# Compiles a pod to all hosts it is attached to.
COMPILE_POD()
{
SPACE_SIGNATURE="podTuple [verbose expectedPodVersion]"
SPACE_DEP="_PRJ_COMPILE_POD"
_PRJ_COMPILE_POD "$@"
}
# Copy configs from general cluster pod config store into this version of the pod.
UPDATE_POD_CONFIG()
{
SPACE_SIGNATURE="podTriple"
SPACE_DEP="_PRJ_UPDATE_POD_CONFIG"
local podTriple="${1}"
shift
_PRJ_UPDATE_POD_CONFIG "${podTriple}"
}
POD_INGRESS_STATE()
{
SPACE_SIGNATURE="state podTriples"
SPACE_DEP="_PRJ_POD_INGRESS_STATE PRINT"
local state="${1}"
shift
if [ -z "${state}" ] || [ "${state}" = "active" ] || [ "${state}" = "inactive" ]; then
# All good, fall through
:
else
PRINT "State must be active, inactive or empty" "error" 0
return 1
fi
_PRJ_POD_INGRESS_STATE "${state}" "$@"
}
SIGNAL_POD()
{
SPACE_SIGNATURE="podTriple [container]"
SPACE_DEP="_PRJ_SIGNAL_POD"
local podTriple="${1}"
shift
_PRJ_SIGNAL_POD "${podTriple}" "$@"
}
DELETE_POD()
{
SPACE_SIGNATURE="podTriples"
SPACE_DEP="_PRJ_DELETE_POD"
_PRJ_DELETE_POD "$@"
}
RERUN_POD()
{
SPACE_SIGNATURE="podTriple [containers]"
SPACE_DEP="_PRJ_ACTION_POD"
local podTriple="${1}"
shift
_PRJ_ACTION_POD "${podTriple}" "rerun" "$@"
}
# Set the pod.version.state file
POD_RELEASE_STATE()
{
SPACE_SIGNATURE="state podTriples"
SPACE_DEP="_PRJ_SET_POD_RELEASE_STATE _PRJ_GET_POD_RELEASE_STATES"
if [ "${1}" = "" ]; then
shift
_PRJ_GET_POD_RELEASE_STATES "$@"
else
_PRJ_SET_POD_RELEASE_STATE "$@"
fi
}
LS_POD_RELEASE_STATE()
{
SPACE_SIGNATURE="filterState:0 quite:0 [podTriple]"
SPACE_DEP="_PRJ_LS_POD_RELEASE_STATE"
_PRJ_LS_POD_RELEASE_STATE "$@"
}
# Connect to the cluster and retrieve logs for a pod instance.
DAEMON_LOG()
{
SPACE_SIGNATURE="[host]"
SPACE_DEP="_PRJ_GET_DAEMON_LOG"
_PRJ_GET_DAEMON_LOG "$@"
}
# Connect to the cluster and retrieve logs for a pod instance.
LOGS()
{
SPACE_SIGNATURE="timestamp:0 limit:0 streams:0 details:0 showProcessLog:0 podTriple [containers]"
SPACE_DEP="_PRJ_GET_POD_LOGS"
# All options are forwarded, the first non positional argument given is expected to be the podTriple.
_PRJ_GET_POD_LOGS "$@"
}
# Generate config for haproxy
GEN_INGRESS_CONFIG()
{
SPACE_SIGNATURE="[podTuple excludeClusterPorts]"
SPACE_DEP="_PRJ_GEN_INGRESS_CONFIG"
_PRJ_GEN_INGRESS_CONFIG "$@"
}
HOST_STATE()
{
SPACE_SIGNATURE="state:0 host"
SPACE_DEP="_PRJ_SET_HOST_STATE _PRJ_GET_HOST_STATE"
if [ "${1}" = "" ]; then
shift
_PRJ_GET_HOST_STATE "$@"
else
_PRJ_SET_HOST_STATE "$@"
fi
}
GET_HOST_STATE()
{
SPACE_SIGNATURE="host"
SPACE_DEP="_PRJ_GET_HOST_STATE"
_PRJ_GET_HOST_STATE "$@"
}
# Check if a specific pod version's instances are ready
GET_POD_STATUS()
{
SPACE_SIGNATURE="readiness:0 quite:0 podTriple"
SPACE_DEP="_PRJ_GET_POD_STATUS"
_PRJ_GET_POD_STATUS "$@"
}
GET_POD_INFO()
{
SPACE_SIGNATURE="podTriple"
SPACE_DEP="_PRJ_GET_POD_INFO"
_PRJ_GET_POD_INFO "$@"
}
RELEASE()
{
SPACE_DEP="_RELEASE"
_RELEASE "$@"
}
POD_SHELL()
{
SPACE_SIGNATURE="useBash container podTriple [commands]"
SPACE_DEP="_PRJ_POD_SHELL"
_PRJ_POD_SHELL "$@"
}
HOST_SHELL()
{
SPACE_SIGNATURE="host [superuser useBash commands]"
SPACE_DEP="_PRJ_HOST_SHELL"
local host="${1}"
shift
local superUser="${1:-false}"
shift $(($# > 0 ? 1 : 0))
local useBash="${1:-false}"
shift $(($# > 0 ? 1 : 0))
_PRJ_HOST_SHELL "${host}" "${superUser}" "${useBash}" "$@"
}
QUICKSTART()
{
printf "%s\\n" "Quickstart:
# Create your management dir
mkdir mgmt-1
cd mgmt-1
# Pull in a pod into your management space
mkdir pods
cd pods
git pull github.com/simplenetes-io/nginx-webserver webserver
git pull github.com/simplenetes-io/ingress
cd ..
# Create a dev cluster for local work
sns create-cluster dev-cluster
cd dev-cluster
sns create-host laptop -a local -d simplenetes/host-laptop -r localhost:32767
sns init-host laptop
sns attach-pod webserver@laptop
sns attach-pod ingress@laptop
sns compile webserver
sns generate-ingress
sns compile ingress
" >&2
}
USAGE()
{
printf "%s\\n" "Usage:
help
-h
Output this help
version
-V
Output the version of Simplenetes
sns CONTEXT COMMAND [OBJECT] [OPTIONS] [ARGUMENTS]
Cluster commands:
cluster create <cluster name>
Creates a cluster project with the given name in the current directory.
A random integer is prefixed to the name to give the cluster its ID.
This ID is stored in the file cluster-id.txt.
cluster ps
Output the current status of the cluster.
cluster sync
Sync this cluster project to the remote network.
-f, --force
Force the sync in case the commit chain does not match.
This is useful when performing a rollback or if restoring a previous branch-out.
-q, --quite
Set to be quite.
--pod-to-overwrite=pod:version
This is a special rescue option used to overwrite an existing release with new files.
First delete the pod:version, then compile it and sync with this option set.
After the update the pod needs to be rerun for changes to take place.
cluster importconfig <pod>
Import config templates from the pod source repo into the cluster project.
cluster geningress [<ingressPod>]
Update the ingress load balancers config by looking at the ingress of all active pod instances on all hosts.
ingressPod
name of the ingress pod to generate configs for, defaults to 'ingress'.
-x, --exclude-cluster-ports=excludeClusterPorts
Comma separated string of clusterPorts to exclude from the Ingress configuration.
cluster registry [<host>|-]
Generate a Docker standard config.json file from data read on stdin.
This file can be used by Podman on the host to authorize to private image registries.
This file is stored as registry-config.json either in the cluster dir or in a specific host dir if the host name is provided as argument.
The file is synced to the host when running 'host setup init', and stored as '~./docker/config.json'.
If you already have an existing Docker 'config.json' file you can place that in in
the cluster dir or in a host dir named as registry-config.json.
If host is set to '-' then output to stdout instead of writing to disk.
This can be useful when manually appending to already existing files.
stdin
Pass data on stdin as (multiple lines allowed):
registry-url:username:password\\n
Host commands:
host register <host>
Register an existing host as part of this cluster.
Note that the physical VM should already have been created prior to running this command.
-a, --address=address (required)
IP[:sshPort] of an existing host.
sshPort defaults to 22.
If address is set to 'local' then that dictates this host is not SSH enabled but targets local disk instead,
which is only useful for when working with a local dev-cluster.
-j, --jump-host=jumpHost
Name of already registered host to use as jumphost.
The name of an already existing host to do SSH jumps via,
often used for worker machines which are not exposed directly to the public internet.
It is allowed to jump through multiple hosts.
-e, --expose=ports
Comma separated list of ports we want to expose to the public internet.
If not provided then the host will be accessible internally only.
The ports listed here are automatically exposed in the firewall when setting up firewall.
If this list is modified in the host.env file then the setup firewall command must be rerun.
-d, --dir-home=hostHome
Directory on host to sync files to.
The default is the host name.
-u, --user-name=username
If set then either the regular user already exists on the host or we set the desired name of the regular user.
-k, --keyfile=userkeyfile
If user is set and already exists on the host then also the keyfile needs to be provided.
A keyfile path can also be provided as the destination of where a new key will be generated,
in the case the key file should be placed outside of the cluster or reused between hosts.
If the user does not exist but a keyfile is provided then that keyfile will be (re-)used for the created user.
Absolute and relative paths can be provided. If relative then it is relative to the host directory.
-s, --super-user-name=superusername
If there is already an existing superuser on the host it must be set here.
Some ISPs provide a superuser instead of root access when creating a VM.
If setting superuser then also set the superuser keyfile with -S.
If superuser is set when registering the host then the create superuser command should not be run.
-S, --super-user-keyfile=superuserkeyfile (recommended if --super-user-name is set)
If the super user is set then also the keyfile can be set.
If not set it defaults to 'id_rsa_super', which must be placed in the host directory.
Absolute and relative paths can be provided. If relative then it is relative to the host directory.
-i, --internal-networks=networks
Comma separated list of networks which are considered internal.
Used for allowing hosts on the same network to connect to each other.
The networks listed here are automatically configured in the host when setting up the firewall.
Default is "192.168.0.0/16,10.0.0.0/8,172.16.0.0/11"
The list can later be modified in the host.env file and then rerun the setup firewall command.
-r, --router-address=routeraddress
The LocalIP:PORT of the router proxy on the host we are registering.
This address is aggregated into a list which is used internally by all the proxies in the cluster.
It should be set to 'internalIP:32767'.
When working with a local dev-cluster with a single host set it to 'localhost:32767' or '127.0.0.1:32767'.
host setup superuser <host>
Login as root on the host and create the super user.
If the superuser was already set when registering the host then this command will not run.
Run this once after 'host register'.
-k, --root-keyfile=rootkeyfile
rootkeyfile is optional, if not set then password is required to login as root.
-s, --super-user-name=superusername
Optionally set the desired name of the superuser to create.
-S, --super-user-keyfile=superuserkeyfile
Point to en existing keyfile to reuse or where to generate the new file.
If not set it defaults to 'id_rsa_super' which will be placed in the host directory.
Absolute and relative paths can be provided. If relative then it is relative to the host directory.
host setup disableroot <host>
Use the super user account to disable the root login on the host.
Run this once after host supet superuser.
host setup install <host>
Use the superuser account to setup the regular user, configure the firewall and install
the simplenetesd systemd service.
Run this command after setup superuser and disableroot.
This command is idempotent and is safe to run multiple times.
If the EXPOSE or INTERNAL variables in host.env are changed then this action need to be run again.
Public keys ('pubkeys/\*.pub') are set in the authorized_keys file on the remote host. Also the current pub key from host.env is added.
Public keys ('pubkeys.superuser/\*.pub') are added to the authorized_keys file on the remote host for the super user. Also the current pub key from host-superuser.env is added.
This command cannot be run for "local" disk based hosts.
Note that superuser must have password free access to the sudo command.
--skip-firewall
Do not make any changes to the firewall
--skip-systemd
Do not (re-)install the simplenetesd systemd unit.
Note that this option will not remove the unit, just not install it.
--skip-podman
Do not install and configure podman.
--strict-user-keys
Only allow public keys put in the host's 'pubkeys' directory to connect to the host as regular user.
Without this option also the current key referenced from host.env is also added.
Use this option to remove your own user from the authorized_keys file on the remote host.
--strict-super-user-keys
Only allow public keys put in the host's 'pubkeys.superuser' directory to connect to the host as the super user.
Without this option also the current key referenced from host-superuser.env is also added.
Use this option to remove your own super user from the authorized_keys file on the remote host.
host init <host>
Initialize a host to be part of the cluster by writing the cluster-id.txt file to
the host home directory.
Also upload the registry-config.json file to the host, which is the Docker config.json
file used to connect to to private image registries.
The json file is searched for in the host directory first, and then in the cluster directory.
Run this command at least once after setup install.
This command is idempotent and is safe to run multiple times.
If the registry-config.json has been updated then run this command again to get it uploaded to the host.
-f, --force
Force a change of the cluster-id.txt. (ps. this can break things).
host ls
List active and inactive hosts in this cluster project.
-p, --pod=pod
Filter on hosts who have a specific pod attached.
-a, --all
If set then also list disabled hosts.
-s, --state
If set then add a host state column to the output.
host attach <pod@host>
Attach a Pod to a host, this does not deploy anything nor release anything.
Host must exist in the cluster project.
Pod must exist on PODPATH, unless --link is provided.
-l, --link optional git url for the pod repo.
If set the repo is cloned into PODPATH if not already existing.
If not set then pod must already exist on PODPATH.
If set and pod already exists then the git urls must match.
If the pod is a git repo the git url will be set in the attachment, so when compiling
the url is verified against the pod and if not existing the pod will be cloned.
If this was the first attachment any pod config templates are imported into the cluster project.
host detach <pod[@host]>
Remove a pod from one or all hosts.
host state <host>
Get or set state of a host.
-s, --state=active|inactive|disabled
If option provided then set the state in the host.state file.
active - has ingress, internal proxy routing and is synced.
inactive - no ingress, no incoming internal proxy routing but is still synced.
Pods can still be attached, compiled and released, but will not get any incoming traffic.
Use this to phase out a host but let it finish it's current sockets.
disabled - no ingress, no incoming internal proxy routing and is not synced. Just ignored.
host logs <host>
Get the simplenetes systemd daemon logs for one or all hosts.
This requires superuser privileges.
host shell <host> [-- <commands>]
Enter an interactive shell on the given host as tne normal user.
-s, --super-user
If set then enter as the superuser.
-b, --bash
Set to force the use of bash as shell, otherwise use sh.
<commands>
Commands are optional and will be run instead of entering the interactive shell.
Commands must be places after any option switches and after a pair of dashes '--', so that arguments are not parsed by sns.
Pod commands:
pod ls [[pod[:version]][@host]]
List pod releases in the cluster.
Optionally provide the pod and/or host to filter by.
If pod is provided without version then all versions are considered. If version is set to 'latest' then only latest releases are considered.
-s, --state=running|stopped|removed|all
Filter for pod state. Default is 'running'.
-q, --quite
Hide the state column.
This can be useful when feeding the output into another command and just wanting the pod.
pod compile <pod[@host]>
Compile the current pod version to all (or one) host(s) which it is already attached to.
If host is left out then compile on all hosts which have the pod attached.
Pod configs stored in the cluster (./_config/) will automatically be copied into the new release.
-v
If option set then output the new pod version to stdout.
This is a porcelain switch used internally.
pod updateconfig <pod[:version][@host]>
Re-copy the cluster pod configs (from ./_config/) to a specific pod release.
This operation is useful when wanting to update configs of an already released pod.
If host is left out then copy configs to the pod on all attached hosts.
If version is left out the 'latest' version is searched for.
pod ingress <pod[:version][@host]>
Get or set the ingress active or inactive state of a specific pod release on one or all attached hosts.
If version is left out the 'latest' version is searched for.
If host is left out then set ingress for pod on all hosts which the pod is attached to.
Note that the ingress needs to be regenerated and the ingress pod updated for the changes to take effect.
Multiple pods can be given on cmd line.
-s, --state=active|inactive
Set the pod(s) ingress state.
If this option is not set then get the state instead of setting it.
pod state <pod[:version][@host]>
Get or set the desired state of a specific pod version on one or all attached hosts.
If version is left out the 'latest' version is searched for on each host.
If host is left out then search all hosts.
Multiple pods can be given as arguments.
The cluster needs to be synced for any changes to take effect.
-s, --state=running|stopped|removed
Set the pod(s) state.
If this option is not set then get the state instead of setting it.
pod ps <pod[:version][@host]>
Get the live status of a pod from the cluster.
If host is left out then get status of the pod for all hosts which the pod is attached to.
If version is left out the 'latest' version is searched for.
-r, --readiness
If option set it means to only get the 'readiness' of the pod.
-q, --quite
If option set it means to not output but to exit with code 1 if no pod ready.
Only applicable if also --readiness flag used.
pod info <pod[:version][@host]>
Get static information on a pod.
If host is left out then get info of the pod for all hosts which the pod is attached to.
If version is left out the 'latest' version is searched for.
pod logs <pod[:version][@host]> [containers]
Output pod logs.
If pod version is left out the 'latest' version is searched for.
If pod host is left out then get pod logs for each attached host.
[containers] can be set to show logs for one or many specific containers. Space separated.
-p, --daemon-process
Show pod daemon process logs (can also be used in combination with [containers])
-t, --timestamp=UNIX timestamp
Time to get logs from, defaults to 0.
If a negative value is given it is seconds relative to now (now-ts).
-s, --stream=stdout|stderr|stdout,stderr
What streams to output.
Defaults to 'stdout,stderr'
-l, --limit=lines
Nr of lines to get in total from the top, negative gets from the bottom (latest).
-d, --details=ts|name|stream|none
Comma separated if many arguments.
if 'ts' set will show the UNIX timestamp for each row.
if 'age' set will show relative age as seconds for each row.
if 'name' is set will show the container name for each row.
if 'stream' is set will show the std stream the logs came on.
To not show any details set to 'none'.
Defaults to 'ts,name'.
pod signal <pod[:version][@host]> [containers]
Signal a pod on a specific host or on all attached hosts.
If pod version is left out the 'latest' version is searched for.
If pod host is left out then get pod logs for each attached host.
Optionally specify which containers to signal, default is all containers in the pod.
pod rerun <pod[:version][@host]> [containers]
Rerun a pod on a specific host or on all attached hosts.
If pod version is left out the 'latest' version is searched for.
If pod host is left out then rerun for each attached host.
Optionally specify which containers to rerun, default is to rerun the whole pod.
pod release <pod[:version]>
Perform the compilation and release of a new pod version.
If 'version' is not provided (or set to 'latest') then compile a new version, if no new version is available quit.
If 'version' is set then re-release that version (which is expected have been compiled already).
This operation expects there to be an Ingress Pod named 'ingress' in the cluster.
A release generates multiple commits in the cluster repo as it proceeds through the stages.
-m, --mode=soft|hard|safe
soft - no downtime, have versions briefly exist concurrently (default mode).
hard - stop old version and start new version in same transaction.
Quick to sync but can give a small glitch in the uptime.
safe - Use this for database pods which access specific files and where
we absolutely do not want them concurrently accessing the same files.
This mode waits until the old version is shutdown before starting the new version.
-p, --push
If set then perform 'git push' operations after each 'git commit'.
This can be desirable when running in a CI/CD environment and we want to resume an aborted release.
-f, --force
If set will force sync changes to cluster even if the commit chain differs.
Use this for rollbacks, or when restoring from a branch-out.
pod shell <pod[:version][@host]> [-- <commands>]
Step into a shell inside a container of a pod.
If version is left out the 'latest' version is searched for.
If host is left out then enter the container on each host, in sequential order.
<commands>
Commands are optional and will be run instead of entering the interactive shell.
Commands must be places after any option switches and after a pair of dashes '--', so that arguments are not parsed by sns.
-c, --container=name
If set then enter the given container.
Default is the last container in the pod specification.
-b, --bash
Set to force the use of bash as shell, otherwise use sh.
pod delete pod[:version][@host]
Delete pod releases which are in the 'removed' state.
If version is left out the 'latest' version is searched for.
If host is left out then delete the pod release version on all attached hosts, as long
as they are in the 'removed' state.
Multiple pods can be provided as arguments.
"
}
SHOW_VERSION()
{
SPACE_ENV="VERSION"
printf "sns %s\\n" "${VERSION}"
}
# options are on the format:
# "_out_all=-a,--all/ _out_state=-s,--state/arg1|arg2|arg3"
# For non argument options the variable will be increased by 1 for each occurrence.
# The variable _out_arguments is reserved for positional arguments.
# Expects _out_arguments and all _out_* to be defined.
_GETOPTS()
{
SPACE_SIGNATURE="options minPositional maxPositional [args]"
SPACE_DEP="_GETOPTS_SWITCH PRINT STRING_SUBSTR STRING_INDEXOF"
local options="${1}"
shift
local minPositional="${1:-0}"
shift
local maxPositional="${1:-0}"
shift
_out_arguments=""
local posCount="0"
local skipOptions="false"
while [ "$#" -gt 0 ]; do
local option=
local value=
local _out_VARNAME=
local _out_ARGUMENTS=
if [ "${skipOptions}" = "false" ] && [ "${1}" = "--" ]; then
skipOptions="true"
shift
continue
fi
if [ "${skipOptions}" = "false" ] && [ "${1#--}" != "${1}" ]; then # Check if it is a double dash GNU option
local l=
STRING_INDEXOF "=" "${1}" "l"
if [ "$?" -eq 0 ]; then
STRING_SUBSTR "${1}" 0 "${l}" "option"
STRING_SUBSTR "${1}" "$((l+1))" "" "value"
else
option="${1}"
fi
shift
# Fill _out_VARNAME and _out_ARGUMENTS
_GETOPTS_SWITCH "${options}" "${option}"
# Fall through to handle option
elif [ "${skipOptions}" = "false" ] && [ "${1#-}" != "${1}" ] && [ "${#1}" -gt 1 ]; then # Check single dash OG-style option
option="${1}"
shift
if [ "${#option}" -gt 2 ]; then
PRINT "Invalid option '${option}'" "error" 0
return 1
fi
# Fill _out_VARNAME and _out_ARGUMENTS
_GETOPTS_SWITCH "${options}" "${option}"
# Do we expect a value to the option? If so take it and shift it out
if [ -n "${_out_ARGUMENTS}" ]; then
if [ "$#" -gt 0 ]; then
value="${1}"
shift
fi
fi
# Fall through to handle option
else
# Positional args
posCount="$((posCount+1))"
if [ "${posCount}" -gt "${maxPositional}" ]; then
PRINT "Too many arguments. Max ${maxPositional} argument(s) allowed." "error" 0
return 1
fi
_out_arguments="${_out_arguments}${_out_arguments:+ }${1}"
shift
continue
fi
# Handle option argument
if [ -z "${_out_VARNAME}" ]; then
PRINT "Unrecognized option: '${option}'" "error" 0
return 1
fi
if [ -n "${_out_ARGUMENTS}" ] && [ -z "${value}" ]; then
# If we are expecting a option arguments but none was provided.
STRING_SUBST "_out_ARGUMENTS" " " ", " 1
PRINT "Option ${option} is expecting an argument like: ${_out_ARGUMENTS}" "error" 0
return 1
elif [ -z "${_out_ARGUMENTS}" ] && [ -z "${value}" ]; then
# This was a simple option without argument, increase counter of occurrences
eval "value=\"\$${_out_VARNAME}\""
if [ -z "${value}" ]; then
value=0
fi
value="$((value+1))"
elif [ "${_out_ARGUMENTS}" = "*" ] || STRING_ITEM_INDEXOF "${_out_ARGUMENTS}" "${value}"; then
# Value is OK, fall through
:
else
# Invalid argument
if [ -z "${_out_ARGUMENTS}" ]; then
PRINT "Option ${option} does not take any arguments" "error" 0
else
PRINT "Invalid ${option} argument '${value}'. Valid arguments are: ${_out_ARGUMENTS}" "error" 0
fi
return 1
fi
# Store arguments in variable
eval "${_out_VARNAME}=\"\${value}\""
done
if [ "${posCount}" -lt "${minPositional}" ]; then
PRINT "Too few arguments provided. Minimum ${minPositional} argument(s) required." "error" 0
return 1
fi
}
# Find a match in options and fill _out_VARNAME and _out_ARGUMENTS
_GETOPTS_SWITCH()
{
SPACE_SIGNATURE="options option"
SPACE_DEP="STRING_SUBST STRING_ITEM_INDEXOF STRING_ITEM_GET STRING_ITEM_COUNT"
local options="${1}"
shift
local option="${1}"
shift
local varname=
local arguments=
local count=0
local index=0
STRING_ITEM_COUNT "${options}" "count"
while [ "${index}" -lt "${count}" ]; do
local item=
STRING_ITEM_GET "${options}" ${index} "item"
varname="${item%%=*}"
arguments="${item#*/}"
local allSwitches="${item#*=}"
allSwitches="${allSwitches%%/*}"
STRING_SUBST "allSwitches" "," " " 1
if STRING_ITEM_INDEXOF "${allSwitches}" "${option}"; then
STRING_SUBST "arguments" "|" " " 1
_out_VARNAME="${varname}"
_out_ARGUMENTS="${arguments}"
return 0
fi
index=$((index+1))
done
# No such option found
return 1
}
SNT_CMDLINE()
{
SPACE_SIGNATURE="[action args]"
SPACE_DEP="USAGE SHOW_VERSION _SNT_CMDLINE FILE_REALPATH PRINT"
SPACE_ENV="CLUSTERPATH PODPATH"
if [ "${1:-help}" = "help" ] || [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
USAGE
return
elif [ "${1:-}" = "version" ] || [ "${1:-}" = "-V" ] || [ "${1:-}" = "--version" ]; then
SHOW_VERSION
return
fi
local oldCwd="${PWD}"
if [ "${1:-}" = "cluster" ] && [ "${2:-}" = "create" ]; then
# When creating a cluster we skip the check about finding the correct working dir.
:
else
# If CLUSTERPATH is given then check so that it is pointing to a cluster.
if [ -n "${CLUSTERPATH}" ]; then
# Check so that cluster-id.txt exists.
if [ ! -f "${CLUSTERPATH}/cluster-id.txt" ]; then