loom-core 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +99 -0
- data/Guardfile +54 -0
- data/Rakefile +6 -0
- data/bin/loom +185 -0
- data/lib/env/development.rb +1 -0
- data/lib/loom.rb +44 -0
- data/lib/loom/all.rb +20 -0
- data/lib/loom/config.rb +106 -0
- data/lib/loom/core_ext.rb +37 -0
- data/lib/loom/dsl.rb +60 -0
- data/lib/loom/facts.rb +13 -0
- data/lib/loom/facts/all.rb +2 -0
- data/lib/loom/facts/fact_file_provider.rb +86 -0
- data/lib/loom/facts/fact_set.rb +138 -0
- data/lib/loom/host_spec.rb +32 -0
- data/lib/loom/inventory.rb +124 -0
- data/lib/loom/logger.rb +141 -0
- data/lib/loom/method_signature.rb +174 -0
- data/lib/loom/mods.rb +4 -0
- data/lib/loom/mods/action_proxy.rb +105 -0
- data/lib/loom/mods/all.rb +3 -0
- data/lib/loom/mods/mod_loader.rb +80 -0
- data/lib/loom/mods/module.rb +113 -0
- data/lib/loom/pattern.rb +15 -0
- data/lib/loom/pattern/all.rb +7 -0
- data/lib/loom/pattern/definition_context.rb +74 -0
- data/lib/loom/pattern/dsl.rb +176 -0
- data/lib/loom/pattern/hook.rb +28 -0
- data/lib/loom/pattern/loader.rb +48 -0
- data/lib/loom/pattern/reference.rb +71 -0
- data/lib/loom/pattern/reference_set.rb +169 -0
- data/lib/loom/pattern/result_reporter.rb +77 -0
- data/lib/loom/runner.rb +209 -0
- data/lib/loom/shell.rb +12 -0
- data/lib/loom/shell/all.rb +10 -0
- data/lib/loom/shell/api.rb +48 -0
- data/lib/loom/shell/cmd_result.rb +33 -0
- data/lib/loom/shell/cmd_wrapper.rb +164 -0
- data/lib/loom/shell/core.rb +226 -0
- data/lib/loom/shell/harness_blob.rb +26 -0
- data/lib/loom/shell/harness_command_builder.rb +50 -0
- data/lib/loom/shell/session.rb +25 -0
- data/lib/loom/trap.rb +44 -0
- data/lib/loom/version.rb +3 -0
- data/lib/loomext/all.rb +4 -0
- data/lib/loomext/corefacts.rb +6 -0
- data/lib/loomext/corefacts/all.rb +8 -0
- data/lib/loomext/corefacts/facter_provider.rb +24 -0
- data/lib/loomext/coremods.rb +5 -0
- data/lib/loomext/coremods/all.rb +13 -0
- data/lib/loomext/coremods/exec.rb +50 -0
- data/lib/loomext/coremods/files.rb +104 -0
- data/lib/loomext/coremods/net.rb +33 -0
- data/lib/loomext/coremods/package/adapter.rb +100 -0
- data/lib/loomext/coremods/package/package.rb +62 -0
- data/lib/loomext/coremods/user.rb +82 -0
- data/lib/loomext/coremods/vm.rb +0 -0
- data/lib/loomext/coremods/vm/all.rb +6 -0
- data/lib/loomext/coremods/vm/vbox.rb +84 -0
- data/loom.gemspec +39 -0
- data/loom/inventory.yml +13 -0
- data/scripts/harness.sh +242 -0
- data/spec/loom/host_spec_spec.rb +101 -0
- data/spec/loom/inventory_spec.rb +154 -0
- data/spec/loom/method_signature_spec.rb +275 -0
- data/spec/loom/pattern/dsl_spec.rb +207 -0
- data/spec/loom/shell/cmd_wrapper_spec.rb +239 -0
- data/spec/loom/shell/harness_blob_spec.rb +42 -0
- data/spec/loom/shell/harness_command_builder_spec.rb +36 -0
- data/spec/runloom.sh +35 -0
- data/spec/scripts/harness_spec.rb +385 -0
- data/spec/spec_helper.rb +94 -0
- data/spec/test.loom +370 -0
- data/spec/test_loom_spec.rb +57 -0
- metadata +287 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require_relative "adapter"
|
3
|
+
|
4
|
+
module LoomExt::CoreMods
|
5
|
+
class Package < Loom::Mods::Module
|
6
|
+
|
7
|
+
UnsupportedPackageManager = Class.new Loom::Mods::ModActionError
|
8
|
+
|
9
|
+
attr_reader :pkg_adapter
|
10
|
+
|
11
|
+
register_mod :pkg
|
12
|
+
|
13
|
+
def init_action
|
14
|
+
@pkg_adapter = default_adapter
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(adapter)
|
18
|
+
case adapter.to_sym
|
19
|
+
when :dnf
|
20
|
+
DnfAdapter.new loom
|
21
|
+
when :rpm
|
22
|
+
RpmAdapter.new loom
|
23
|
+
when :apt
|
24
|
+
AptAdapter.new loom
|
25
|
+
when :dpkg
|
26
|
+
DpkgAdapter.new loom
|
27
|
+
when :gem
|
28
|
+
GemAdapter.new loom
|
29
|
+
else
|
30
|
+
raise UnsupportedPackageManager, adapter
|
31
|
+
end
|
32
|
+
end
|
33
|
+
alias_method :[], :get
|
34
|
+
|
35
|
+
def default_adapter
|
36
|
+
if loom.test :which, "dnf"
|
37
|
+
DnfAdapter.new loom
|
38
|
+
elsif loom.test :which, "rpm"
|
39
|
+
RpmAdapter.new loom
|
40
|
+
elsif loom.test :which, "apt"
|
41
|
+
AptAdapter.new loom
|
42
|
+
elsif loom.test :which, "dpkg"
|
43
|
+
DpkgAdapter.new loom
|
44
|
+
else
|
45
|
+
raise UnsupportedPackageManager
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Actions
|
50
|
+
extend Forwardable
|
51
|
+
def_delegators :@pkg_adapter, :installed?, :install, :uninstall,
|
52
|
+
:update_cache, :upgrade, :ensure_installed
|
53
|
+
|
54
|
+
def [](*args)
|
55
|
+
get(*args)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
import_actions Package::Actions
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module LoomExt::CoreMods
|
2
|
+
class User < Loom::Mods::Module
|
3
|
+
|
4
|
+
SudoersDNoExistError = Class.new Loom::Mods::ModActionError
|
5
|
+
SudoersDNotIncluded = Class.new Loom::Mods::ModActionError
|
6
|
+
|
7
|
+
register_mod :user
|
8
|
+
required_commands :useradd, :userdel, :getent
|
9
|
+
|
10
|
+
SUDOERS_FILE = "/etc/sudoers"
|
11
|
+
SUDOERS_DIR = "/etc/sudoers.d"
|
12
|
+
LOOM_SUDOERS_FILE = SUDOERS_DIR + "/90-loom-sudoers"
|
13
|
+
|
14
|
+
def user_exists?(user)
|
15
|
+
shell.test :getent, :passwd, user
|
16
|
+
end
|
17
|
+
|
18
|
+
def includes_sudoers?
|
19
|
+
shell.test :grep, :"-e", :"'^#includedir #{SUDOERS_DIR}$'", SUDOERS_FILE
|
20
|
+
end
|
21
|
+
|
22
|
+
def sudoersd_exists?
|
23
|
+
shell.test :test, %Q[-d #{SUDOERS_DIR}]
|
24
|
+
end
|
25
|
+
|
26
|
+
module Actions
|
27
|
+
def add(user,
|
28
|
+
home_dir: nil,
|
29
|
+
login_shell: "/bin/bash",
|
30
|
+
uid: nil,
|
31
|
+
gid: nil,
|
32
|
+
groups: [],
|
33
|
+
is_system_user: nil)
|
34
|
+
if user_exists? user
|
35
|
+
Loom.log.warn "add_user skipping existing user => #{user}"
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
flags = []
|
40
|
+
flags << ["--home-dir", home_dir] if home_dir
|
41
|
+
flags << ["--create-home"] if home_dir
|
42
|
+
flags << ["--shell", login_shell] if login_shell
|
43
|
+
flags << ["--uid", uid] if uid
|
44
|
+
flags << ["--gid", gid] if gid
|
45
|
+
flags << ["--groups", groups] unless groups.empty?
|
46
|
+
flags << "--system" if is_system_user
|
47
|
+
|
48
|
+
loom.exec :useradd, flags, user
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_system_user(user, **user_fields)
|
52
|
+
if user_exists? user
|
53
|
+
Loom.log.warn "add_system_user skipping existing user => #{user}"
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
add user, is_system_user: true, login_shell: "/bin/false", **user_fields
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove(user)
|
61
|
+
unless user_exists? user
|
62
|
+
Loom.log.warn "remove_user skipping non-existant user => #{user}"
|
63
|
+
return
|
64
|
+
end
|
65
|
+
|
66
|
+
loom.exec :userdel, "-r", user
|
67
|
+
end
|
68
|
+
|
69
|
+
def make_sudoer(user)
|
70
|
+
raise SudoersDNotIncluded unless includes_sudoers?
|
71
|
+
raise SudoersDNoExistError unless sudoersd_exists?
|
72
|
+
|
73
|
+
sudoer_conf = :"#{user} ALL=(ALL) NOPASSWD:ALL"
|
74
|
+
|
75
|
+
loom.files(LOOM_SUDOERS_FILE).append sudoer_conf
|
76
|
+
loom.exec :chmod, "0440", LOOM_SUDOERS_FILE
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
User.import_actions User::Actions
|
82
|
+
end
|
File without changes
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module LoomExt::CoreMods::VM
|
2
|
+
class Virtualbox < Loom::Mods::Module
|
3
|
+
|
4
|
+
DuplicateVMImport = Class.new Loom::ExecutionError
|
5
|
+
UnknownVM = Class.new Loom::ExecutionError
|
6
|
+
|
7
|
+
register_mod :vbox
|
8
|
+
required_commands :vboxmanage
|
9
|
+
|
10
|
+
module Actions
|
11
|
+
def check_exists(vm)
|
12
|
+
loom.test "vboxmanage showvminfo #{vm}".split
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_running(vm)
|
16
|
+
loom.test "vboxmanage list runningvms".split, :piped_cmds => [
|
17
|
+
"grep \"#{vm}\"".split
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
def list
|
22
|
+
loom << "vboxmanage list vms".split
|
23
|
+
end
|
24
|
+
|
25
|
+
def snapshot(vm, action: :take, snapshot_name: nil)
|
26
|
+
raise UnknownVM, vm unless check_exists(vm)
|
27
|
+
|
28
|
+
cmd = ["vboxmanage snapshot #{vm} #{action}"]
|
29
|
+
cmd << snapshot_name if snapshot_name
|
30
|
+
cmd = cmd.join " "
|
31
|
+
|
32
|
+
loom << cmd.split
|
33
|
+
end
|
34
|
+
|
35
|
+
def import(ova_file, vm, disk, take_snapshot: true)
|
36
|
+
raise DuplicateVMImport, vm if check_exists(vm)
|
37
|
+
|
38
|
+
loom << "vboxmanage import #{ova_file} \
|
39
|
+
--vsys 0 --vmname #{vm} \
|
40
|
+
--vsys 0 --unit 12 --disk '#{disk}'".split
|
41
|
+
|
42
|
+
if take_snapshot
|
43
|
+
snapshot vm, action: :take, snapshot_name: "#{vm}:import"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def clone(src_vm, dst_vm, options: :link, snapshot: nil, take_snapshot: true)
|
48
|
+
raise DuplicateVMImport, "VM already exists => #{dst_vm}" if check_exists(dst_vm)
|
49
|
+
raise UnknownVM, src_vm unless check_exists(src_vm)
|
50
|
+
|
51
|
+
cmd = ["vboxmanage clonevm #{src_vm}"]
|
52
|
+
cmd << "--snapshot #{snapshot}" if snapshot
|
53
|
+
cmd << "--options #{options}" if options
|
54
|
+
cmd << "--name #{dst_vm}"
|
55
|
+
cmd << "--register"
|
56
|
+
cmd = cmd.join " "
|
57
|
+
|
58
|
+
loom << cmd.split
|
59
|
+
|
60
|
+
if take_snapshot
|
61
|
+
snapshot dst_vm, action: :take, snapshot_name: "#{dst_vm}:clone"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def up(vm)
|
66
|
+
unless check_running(vm)
|
67
|
+
loom << "vboxmanage startvm #{vm} --type headless".split
|
68
|
+
else
|
69
|
+
Loom.log.warn "VM #{vm} already running, nothing to do"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def down(vm)
|
74
|
+
if check_running(vm)
|
75
|
+
loom << "vboxmanage controlvm #{vm} acpipowerbutton".split
|
76
|
+
else
|
77
|
+
Loom.log.warn "VM #{vm} not running, nothing to do"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
import_actions Actions
|
83
|
+
end
|
84
|
+
end
|
data/loom.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path '../lib/', __FILE__
|
2
|
+
require 'loom/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'loom-core'
|
6
|
+
s.description = 'Repeatable management of remote hosts over SSH'
|
7
|
+
s.summary = s.description
|
8
|
+
s.version = Loom::VERSION
|
9
|
+
s.license = 'MIT'
|
10
|
+
s.authors = ['Erick Johnson']
|
11
|
+
s.email = 'ejohnson82@gmail.com'
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
16
|
+
s.require_paths = %w[lib]
|
17
|
+
|
18
|
+
s.add_dependency 'sshkit', '~> 1.11'
|
19
|
+
s.add_dependency 'commander', '~> 4.4'
|
20
|
+
|
21
|
+
# Need net-ssh beta and its explicit requirements until for ed25519
|
22
|
+
# elliptic curve key support
|
23
|
+
# https://github.com/net-ssh/net-ssh/issues/214
|
24
|
+
|
25
|
+
# grrr.. 4.x.beta won't work in `gem install` until the official
|
26
|
+
# release due to net-scp gem dependencies.
|
27
|
+
# I can manually `gem install net-ssh --version 4.0.0.beta3` for now.
|
28
|
+
# s.add_dependency 'net-ssh', '>= 4.0.0.beta3'
|
29
|
+
s.add_dependency 'net-ssh', '>= 3'
|
30
|
+
s.add_dependency 'rbnacl-libsodium', '1.0.10'
|
31
|
+
s.add_dependency 'bcrypt_pbkdf', '1.0.0.alpha1'
|
32
|
+
|
33
|
+
s.add_development_dependency 'bundler', '~> 1.13'
|
34
|
+
s.add_development_dependency 'rake', '~> 11.3'
|
35
|
+
s.add_development_dependency 'rspec', '~> 3.5'
|
36
|
+
s.add_development_dependency 'guard-rspec', '~> 4.7'
|
37
|
+
s.add_development_dependency 'pry', '~> 0.10'
|
38
|
+
s.add_development_dependency 'pry-byebug'
|
39
|
+
end
|
data/loom/inventory.yml
ADDED
data/scripts/harness.sh
ADDED
@@ -0,0 +1,242 @@
|
|
1
|
+
# The Harness script for encoding, checksum'ing and running loom
|
2
|
+
# patterns.
|
3
|
+
#
|
4
|
+
# The point of the harness is to safely encode arbitrary commands as
|
5
|
+
# base64 strings and execute them in another shell, usually on a
|
6
|
+
# remote machine over SSH. The flow for running the harness is:
|
7
|
+
#
|
8
|
+
# 1. base64 encode an arbitrary shell script, this is the encoded
|
9
|
+
# script
|
10
|
+
# 2. get a checksum for the encoded script
|
11
|
+
# 3. send the encoded script and checksum to a shell in another
|
12
|
+
# process (local or remote) to invoke the encoded script via this
|
13
|
+
# harness script
|
14
|
+
#
|
15
|
+
# Given 2 hosts, [local] and [remote] the process looks like this:
|
16
|
+
#
|
17
|
+
# [local]$ encoded=$(./scripts/harness.sh --print_base64 - <<'EOS'
|
18
|
+
# echo my sweet script
|
19
|
+
# EOS
|
20
|
+
# )
|
21
|
+
# [local]$ checksum=$(./scripts/harness --print_checksum $encoded)
|
22
|
+
#
|
23
|
+
# ... SCP harness.sh to some/path on remote ...
|
24
|
+
#
|
25
|
+
# [local]$ ssh user@remote \
|
26
|
+
# some/path/harness.sh --run - $checksum <<EOS
|
27
|
+
# $encoded
|
28
|
+
# EOS
|
29
|
+
#
|
30
|
+
# There are 2 different shells that the harness deals with. The
|
31
|
+
# harness shell, and the command shell.
|
32
|
+
#
|
33
|
+
# The harness shell is the shell used to run the harness script (this
|
34
|
+
# file). Only POSIX features are supported in the harness
|
35
|
+
# script. Officially, `bash`, `bash --posix`, and `dash` are suported
|
36
|
+
# via the specs, (see spec/scripts/harness_spec.rb). Unofficially, any
|
37
|
+
# POSIX compliant shell should work.
|
38
|
+
#
|
39
|
+
# The command shell is the shell used by the harness to execute the
|
40
|
+
# encoded script. By default the command shell is `/bin/sh`. The
|
41
|
+
# command shell can be whatever you choose by passing an additonal
|
42
|
+
# parameter to `harness.sh --run`. For example, to run the encoded
|
43
|
+
# script in dash:
|
44
|
+
#
|
45
|
+
# [local]$ harness.sh --run - $checksum --cmd_shell /bin/dash <<EOS
|
46
|
+
# $encoded
|
47
|
+
# EOS
|
48
|
+
#
|
49
|
+
# To run the harness script in bash POSIX mode and the command script
|
50
|
+
# in plain old bash, the following will work:
|
51
|
+
#
|
52
|
+
# [local]$ (bash --posix -) <<HARNESS_EOS
|
53
|
+
# harness.sh --run - $checksum --cmd_shell /bin/bash <<COMMAND_EOS
|
54
|
+
# $encoded
|
55
|
+
# COMMAND_EOS
|
56
|
+
# HARNESS_EOS
|
57
|
+
#
|
58
|
+
# Commands will be recored as they are executed in the record file. By
|
59
|
+
# default the record file is /dev/null. To use a record file pass the
|
60
|
+
# record_file argument to --run, e.g.:
|
61
|
+
#
|
62
|
+
# harness.sh --run - $checksum --record_file /opt/loom/cmds <<CMDS...
|
63
|
+
#
|
64
|
+
|
65
|
+
declare -r DEFAULT_COMMAND_SHELL="/bin/sh"
|
66
|
+
declare -r DEFAULT_RECORD_FILE="/dev/null"
|
67
|
+
|
68
|
+
declare -r TRUE=0
|
69
|
+
declare -r FALSE=1
|
70
|
+
|
71
|
+
declare -r SUCCESS=0
|
72
|
+
|
73
|
+
declare -r EXIT_INVALID_BASE64=9
|
74
|
+
declare -r EXIT_BAD_CHECKSUM=8
|
75
|
+
declare -r EXIT_MISSING_ARG=2
|
76
|
+
declare -r EXIT_GENERIC=1
|
77
|
+
|
78
|
+
exit_with_usage() {
|
79
|
+
script=$(basename "$0")
|
80
|
+
echo "Usages:"
|
81
|
+
echo " ${script} --check <base64_blob|-> <golden_checksum>"
|
82
|
+
echo " ${script} --run <base64_blob|-> <golden_checksum> \\"
|
83
|
+
echo " [--cmd_shell shell] \\"
|
84
|
+
echo " [--record_file record_file]"
|
85
|
+
echo " ${script} --print_checksum <base64_blob|->"
|
86
|
+
echo " ${script} --print_base64 <raw_cmds|->"
|
87
|
+
exit $EXIT_GENERIC
|
88
|
+
}
|
89
|
+
|
90
|
+
##
|
91
|
+
# If $0 equals "-", then consume and return STDIN, otherwise return
|
92
|
+
# the value.
|
93
|
+
value_or_stdin() {
|
94
|
+
local value="${1}"
|
95
|
+
|
96
|
+
if [ "${value}" = "-" ]; then
|
97
|
+
echo "read stdin" 1>&2
|
98
|
+
(cat)<&0
|
99
|
+
else
|
100
|
+
echo "read value arg" 1>&2
|
101
|
+
echo -n $value
|
102
|
+
fi
|
103
|
+
}
|
104
|
+
|
105
|
+
base64_encode_cmds() {
|
106
|
+
local raw_cmds="$1"
|
107
|
+
echo $(base64 -w0 <<BASE64_EOF
|
108
|
+
${raw_cmds}
|
109
|
+
BASE64_EOF
|
110
|
+
)
|
111
|
+
}
|
112
|
+
|
113
|
+
validate_base64_blob() {
|
114
|
+
local unknown_blob="$1"
|
115
|
+
(base64 -d <<BASE64_EOF
|
116
|
+
${unknown_blob}
|
117
|
+
BASE64_EOF
|
118
|
+
) > /dev/null
|
119
|
+
if [ ! "$?" -eq 0 ]; then
|
120
|
+
exit $EXIT_INVALID_BASE64
|
121
|
+
fi
|
122
|
+
}
|
123
|
+
|
124
|
+
validate_arg_is_present() {
|
125
|
+
arg="$1"
|
126
|
+
msg="$2"
|
127
|
+
if [ -z "${arg}" ]; then
|
128
|
+
echo "${msg}" 1>&2
|
129
|
+
exit $EXIT_MISSING_ARG
|
130
|
+
fi
|
131
|
+
}
|
132
|
+
|
133
|
+
print_checksum() {
|
134
|
+
local chksum_blob="$1"
|
135
|
+
|
136
|
+
echo "checksum'ing base64 blob: +${chksum_blob}+" 1>&2
|
137
|
+
echo $(sha1sum - <<CHECKSUM_EOF | cut -d' ' -f1
|
138
|
+
${chksum_blob}
|
139
|
+
CHECKSUM_EOF
|
140
|
+
)
|
141
|
+
}
|
142
|
+
|
143
|
+
check_cmds() {
|
144
|
+
local base64_blob="$1"
|
145
|
+
local golden_sha1="$2"
|
146
|
+
local actual_sha1=$(print_checksum "${base64_blob}")
|
147
|
+
|
148
|
+
test "${golden_sha1}" = "${actual_sha1}"
|
149
|
+
}
|
150
|
+
|
151
|
+
run_cmds() {
|
152
|
+
local base64_blob="$1"
|
153
|
+
local cmd_shell="${2:-$DEFAULT_COMMAND_SHELL}"
|
154
|
+
local record_file="${3:-$DEFAULT_RECORD_FILE}"
|
155
|
+
(
|
156
|
+
base64 -d | tee -a ${record_file} | ${cmd_shell} -
|
157
|
+
) <<RUN_EOS
|
158
|
+
${base64_blob}
|
159
|
+
RUN_EOS
|
160
|
+
}
|
161
|
+
|
162
|
+
main() {
|
163
|
+
set -xv
|
164
|
+
local flag="$1"
|
165
|
+
local should_run=$FALSE
|
166
|
+
shift
|
167
|
+
|
168
|
+
if [ -z "${flag}" ]; then
|
169
|
+
exit_with_usage
|
170
|
+
fi
|
171
|
+
|
172
|
+
case $flag in
|
173
|
+
--print_base64)
|
174
|
+
declare -r raw_cmds=$(value_or_stdin "$1")
|
175
|
+
declare -r base64_blob=$(base64_encode_cmds "${raw_cmds}")
|
176
|
+
validate_base64_blob "${base64_blob}"
|
177
|
+
|
178
|
+
printf $base64_blob
|
179
|
+
exit $SUCCESS
|
180
|
+
;;
|
181
|
+
--print_checksum)
|
182
|
+
declare -r base64_blob=$(value_or_stdin "$1")
|
183
|
+
validate_base64_blob "${base64_blob}"
|
184
|
+
|
185
|
+
printf $(print_checksum "${base64_blob}")
|
186
|
+
exit $SUCCESS
|
187
|
+
;;
|
188
|
+
--check)
|
189
|
+
declare -r base64_blob=$(value_or_stdin "$1")
|
190
|
+
declare -r golden_sha1="$2"
|
191
|
+
shift
|
192
|
+
shift
|
193
|
+
;;
|
194
|
+
--run)
|
195
|
+
should_run=$TRUE
|
196
|
+
declare -r base64_blob=$(value_or_stdin "$1")
|
197
|
+
declare -r golden_sha1="$2"
|
198
|
+
shift
|
199
|
+
shift
|
200
|
+
|
201
|
+
while (( "$#" >= 2 )); do
|
202
|
+
case "$1" in
|
203
|
+
--cmd_shell)
|
204
|
+
declare -r cmd_shell="$2"
|
205
|
+
shift
|
206
|
+
shift
|
207
|
+
;;
|
208
|
+
--record_file)
|
209
|
+
declare -r record_file="$2"
|
210
|
+
shift
|
211
|
+
shift
|
212
|
+
;;
|
213
|
+
*)
|
214
|
+
echo "unknown arg for --run: ${1}" 1>&2
|
215
|
+
exit_with_usage
|
216
|
+
shift
|
217
|
+
;;
|
218
|
+
esac
|
219
|
+
shift
|
220
|
+
done
|
221
|
+
;;
|
222
|
+
*)
|
223
|
+
exit_with_usage
|
224
|
+
;;
|
225
|
+
esac
|
226
|
+
|
227
|
+
validate_arg_is_present "${base64_blob}" "missing base64_blob"
|
228
|
+
validate_arg_is_present "${golden_sha1}" "missing golden_sha1"
|
229
|
+
validate_base64_blob "${base64_blob}"
|
230
|
+
|
231
|
+
if ! (check_cmds "${base64_blob}" "${golden_sha1}"); then
|
232
|
+
echo "checksum failed, expected ${golden_sha1}" 1>&2
|
233
|
+
exit $EXIT_BAD_CHECKSUM
|
234
|
+
fi
|
235
|
+
|
236
|
+
if [ "${should_run}" -eq $TRUE ]; then
|
237
|
+
echo "running commands" 1>&2
|
238
|
+
run_cmds "${base64_blob}" "${cmd_shell}" "${record_file}"
|
239
|
+
fi
|
240
|
+
}
|
241
|
+
|
242
|
+
main "$@"
|