summaryrefslogtreecommitdiff
path: root/lib/leap_cli
diff options
context:
space:
mode:
Diffstat (limited to 'lib/leap_cli')
-rw-r--r--lib/leap_cli/commands/deploy.rb4
-rw-r--r--lib/leap_cli/commands/node.rb74
-rw-r--r--lib/leap_cli/commands/pre.rb5
-rw-r--r--lib/leap_cli/commands/vagrant.rb39
-rw-r--r--lib/leap_cli/config/object.rb15
-rw-r--r--lib/leap_cli/path.rb25
-rw-r--r--lib/leap_cli/util.rb57
7 files changed, 174 insertions, 45 deletions
diff --git a/lib/leap_cli/commands/deploy.rb b/lib/leap_cli/commands/deploy.rb
index bee09a0..f94465f 100644
--- a/lib/leap_cli/commands/deploy.rb
+++ b/lib/leap_cli/commands/deploy.rb
@@ -16,6 +16,10 @@ module LeapCli
end
end
+ nodes.each_node do |node|
+ assert_files_exist! Path.named_path([:hiera, node.name]), :msg => 'try running `leap compile`'
+ end
+
ssh_connect(nodes) do |ssh|
ssh.leap.assert_initialized
diff --git a/lib/leap_cli/commands/node.rb b/lib/leap_cli/commands/node.rb
index 9bf27e2..f208f87 100644
--- a/lib/leap_cli/commands/node.rb
+++ b/lib/leap_cli/commands/node.rb
@@ -10,16 +10,41 @@ module LeapCli; module Commands
desc 'Node management'
command :node do |node|
node.desc 'Create a new configuration file for a node'
+ node.long_desc ["If specified, the optional argument seed-options can be used to seed values in the node configuration file.",
+ "The format is property_name:value.",
+ "For example: `leap node add web1 ip_address:1.2.3.4 services:webapp`.",
+ "To set nested properties, property name can contain '.', like so: `leap node add web1 ssh.port:44`",
+ "To set multiple values for a single property, use ',', like so: `leap node add mynode services:webapp,dns`"].join("\n\n")
+ node.arg_name '<node-name> [seed-options]' # , :optional => false, :multiple => false
node.command :add do |add|
+ add.switch :local, :desc => 'Make a local testing node (by automatically assigning the next available local IP address). Local nodes are run as virtual machines on your computer.', :negatable => false
add.action do |global_options,options,args|
- log 'not yet implemented'
+ # argument sanity checks
+ name = args.first
+ assert! name, 'No <node-name> specified.'
+ assert! name =~ /^[0-9a-z_-]+$/, "illegal characters used in node name '#{name}'"
+ assert_files_missing! [:node_config, node.name]
+
+ # create and seed new node
+ node = Config::Object.new
+ if options[:local]
+ node['ip_address'] = pick_next_vagrant_ip_address
+ end
+ seed_node_data(node, args[1..-1])
+
+ # write the file
+ write_file! [:node_config, name], node.dump_json + "\n"
end
end
- node.desc 'Bootstraps a node, setting up ssh keys and installing prerequisites'
- node.arg_name 'node-name', :optional => false, :multiple => false
+ node.desc 'Bootstraps a node, setting up SSH keys and installing prerequisite packages'
+ node.long_desc "This command prepares a server to be used with the LEAP Platform by saving the server's SSH host key, " +
+ "copying the authorized_keys file, and installing packages that are required for deploying. " +
+ "Node init must be run before deploying to a server, and the server must be running and available via the network. " +
+ "This command only needs to be run once, but there is no harm in running it multiple times."
+ node.arg_name '<node-name>' #, :optional => false, :multiple => false
node.command :init do |init|
- init.switch 'echo', :desc => 'if set, passwords are visible as you type them (default is hidden)', :negatable => false
+ init.switch 'echo', :desc => 'If set, passwords are visible as you type them (default is hidden)', :negatable => false
init.action do |global_options,options,args|
node = get_node_from_args(args)
ping_node(node)
@@ -34,17 +59,30 @@ module LeapCli; module Commands
end
node.desc 'Renames a node file, and all its related files'
+ node.arg_name '<old-name> <new-name>'
node.command :mv do |mv|
mv.action do |global_options,options,args|
- log 'not yet implemented'
+ node = get_node_from_args(args)
+ new_name = args.last
+ ensure_dir [:node_files_dir, new_name]
+ Path::NODE_PATHS.each do |path|
+ rename_file! [path, node.name], [path, new_name]
+ end
+ remove_directory! [:node_files_dir, node.name]
end
end
node.desc 'Removes a node file, and all its related files'
- node.arg_name '<node-name>', :optional => false, :multiple => false
+ node.arg_name '<node-name>' #:optional => false #, :multiple => false
node.command :rm do |rm|
rm.action do |global_options,options,args|
- log 'not yet implemented'
+ node = get_node_from_args(args)
+ (Path::NODE_PATHS + [:node_files_dir]).each do |path|
+ remove_file! [path, node.name]
+ end
+ if node.vagrant?
+ vagrant_command("destroy --force", [node.name])
+ end
end
end
end
@@ -135,4 +173,26 @@ module LeapCli; module Commands
assert_run!("ping -W 1 -c 1 #{node.ip_address}", "Could not ping #{node.name} (address #{node.ip_address}). Try again, we only send a single ping.")
end
+ def seed_node_data(node, args)
+ args.each do |seed|
+ key, value = seed.split(':')
+ if value =~ /,/
+ value = value.split(',')
+ end
+ assert! key =~ /^[0-9a-z\._]+$/, "illegal characters used in property '#{key}'"
+ if key =~ /\./
+ key_parts = key.split('.')
+ final_key = key_parts.pop
+ current_object = node
+ key_parts.each do |key_part|
+ current_object[key_part] = Config::Object.new
+ current_object = current_object[key_part]
+ end
+ current_object[final_key] = value
+ else
+ node[key] = value
+ end
+ end
+ end
+
end; end \ No newline at end of file
diff --git a/lib/leap_cli/commands/pre.rb b/lib/leap_cli/commands/pre.rb
index cae787e..346814b 100644
--- a/lib/leap_cli/commands/pre.rb
+++ b/lib/leap_cli/commands/pre.rb
@@ -40,6 +40,11 @@ module LeapCli
end
#
+ # load all the nodes everything
+ #
+ manager
+
+ #
# check requirements
#
REQUIREMENTS.each do |key|
diff --git a/lib/leap_cli/commands/vagrant.rb b/lib/leap_cli/commands/vagrant.rb
index cd3e71b..a9c2928 100644
--- a/lib/leap_cli/commands/vagrant.rb
+++ b/lib/leap_cli/commands/vagrant.rb
@@ -10,7 +10,6 @@ module LeapCli; module Commands
local.arg_name 'node-filter', :optional => true #, :multiple => false
local.command :start do |start|
start.action do |global_options,options,args|
- vagrant_setup
vagrant_command(["up", "sandbox on"], args)
end
end
@@ -19,7 +18,6 @@ module LeapCli; module Commands
local.arg_name 'node-filter', :optional => true #, :multiple => false
local.command :stop do |stop|
stop.action do |global_options,options,args|
- vagrant_setup
vagrant_command("halt", args)
end
end
@@ -28,7 +26,6 @@ module LeapCli; module Commands
local.arg_name 'node-filter', :optional => true #, :multiple => false
local.command :reset do |reset|
reset.action do |global_options,options,args|
- vagrant_setup
vagrant_command("sandbox rollback", args)
end
end
@@ -37,7 +34,6 @@ module LeapCli; module Commands
local.arg_name 'node-filter', :optional => true #, :multiple => false
local.command :destroy do |destroy|
destroy.action do |global_options,options,args|
- vagrant_setup
vagrant_command("destroy", args)
end
end
@@ -46,7 +42,6 @@ module LeapCli; module Commands
local.arg_name 'node-filter', :optional => true #, :multiple => false
local.command :status do |status|
status.action do |global_options,options,args|
- vagrant_setup
vagrant_command("status", args)
end
end
@@ -66,18 +61,10 @@ module LeapCli; module Commands
return file_path
end
- private
-
- def vagrant_setup
- assert_bin! 'vagrant', 'run "sudo gem install vagrant"'
- unless `vagrant gem which sahara`.chars.any?
- log :installing, "vagrant plugin 'sahara'"
- assert_run! 'vagrant gem install sahara'
- end
- create_vagrant_file
- end
+ protected
def vagrant_command(cmds, args)
+ vagrant_setup
cmds = cmds.to_a
assert_config! 'provider.vagrant.network'
if args.empty?
@@ -99,6 +86,17 @@ module LeapCli; module Commands
end
end
+ private
+
+ def vagrant_setup
+ assert_bin! 'vagrant', 'run "sudo gem install vagrant"'
+ unless `vagrant gem which sahara`.chars.any?
+ log :installing, "vagrant plugin 'sahara'"
+ assert_run! 'vagrant gem install sahara'
+ end
+ create_vagrant_file
+ end
+
def execute(cmd)
log 2, :run, cmd
exec cmd
@@ -123,4 +121,15 @@ module LeapCli; module Commands
write_file! :vagrantfile, lines.join("\n")
end
+ def pick_next_vagrant_ip_address
+ taken_ips = manager.nodes[:local => true].field(:ip_address)
+ if taken_ips.any?
+ highest_ip = taken_ips.map{|ip| IPAddr.new(ip)}.max
+ new_ip = highest_ip.succ
+ else
+ new_ip = IPAddr.new(manager.provider.vagrant.network).succ.succ
+ end
+ return new_ip.to_s
+ end
+
end; end \ No newline at end of file
diff --git a/lib/leap_cli/config/object.rb b/lib/leap_cli/config/object.rb
index bbaa6f4..155b51f 100644
--- a/lib/leap_cli/config/object.rb
+++ b/lib/leap_cli/config/object.rb
@@ -199,9 +199,18 @@ module LeapCli
# returns true if this node has an ip address in the range of the vagrant network
#
def vagrant?
- vagrant_range = IPAddr.new @manager.provider.vagrant.network
- ip_address = IPAddr.new @node.ip_address
- vagrant_range.include?(ip_address)
+ begin
+ vagrant_range = IPAddr.new @manager.provider.vagrant.network
+ rescue ArgumentError => exc
+ Util::bail! { Util::log :invalid, "ip address '#{@node.ip_address}' vagrant.network" }
+ end
+
+ begin
+ ip_address = IPAddr.new @node.get('ip_address')
+ rescue ArgumentError => exc
+ Util::log :warning, "invalid ip address '#{@node.get('ip_address')}' for node '#{@node.name}'"
+ end
+ return vagrant_range.include?(ip_address)
end
##
diff --git a/lib/leap_cli/path.rb b/lib/leap_cli/path.rb
index 20994f4..43f2edc 100644
--- a/lib/leap_cli/path.rb
+++ b/lib/leap_cli/path.rb
@@ -2,6 +2,9 @@ require 'fileutils'
module LeapCli; module Path
+ #
+ # all the named paths, relative to provider directory.
+ #
NAMED_PATHS = {
# directories
:hiera_dir => 'hiera',
@@ -23,16 +26,9 @@ module LeapCli; module Path
:provider_json_template => 'files/service-definitions/provider.json.erb',
:eip_service_json_template => 'files/service-definitions/eip-service.json.erb',
- # input data files
- :commercial_cert => 'files/cert/#{arg}.crt',
- :commercial_key => 'files/cert/#{arg}.key',
- :commercial_csr => 'files/cert/#{arg}.csr',
-
# output files
:user_ssh => 'users/#{arg}/#{arg}_ssh.pub',
:user_pgp => 'users/#{arg}/#{arg}_pgp.pub',
- :hiera => 'hiera/#{arg}.yaml',
- :node_ssh_pub_key => 'files/nodes/#{arg}/#{arg}_ssh.pub',
:known_hosts => 'files/ssh/known_hosts',
:authorized_keys => 'files/ssh/authorized_keys',
:ca_key => 'files/ca/ca.key',
@@ -42,10 +38,14 @@ module LeapCli; module Path
:commercial_csr => 'files/cert/#{arg}.csr',
:commercial_cert => 'files/cert/#{arg}.crt',
:commercial_ca_cert => 'files/cert/commercial_ca.crt',
- :node_x509_key => 'files/nodes/#{arg}/#{arg}.key',
- :node_x509_cert => 'files/nodes/#{arg}/#{arg}.crt',
:vagrantfile => 'test/Vagrantfile',
+ # node output files
+ :hiera => 'hiera/#{arg}.yaml',
+ :node_ssh_pub_key => 'files/nodes/#{arg}/#{arg}_ssh.pub',
+ :node_x509_key => 'files/nodes/#{arg}/#{arg}.key',
+ :node_x509_cert => 'files/nodes/#{arg}/#{arg}.crt',
+
# testing files
:test_client_key => 'test/cert/client.key',
:test_client_cert => 'test/cert/client.crt',
@@ -53,6 +53,13 @@ module LeapCli; module Path
:test_client_openvpn_template => 'test/openvpn/client.ovpn.erb'
}
+ #
+ # paths that take node name as the argument
+ #
+ NODE_PATHS = [
+ :node_config, :hiera, :node_x509_cert, :node_x509_key, :node_ssh_pub_key
+ ]
+
def self.platform
@platform
end
diff --git a/lib/leap_cli/util.rb b/lib/leap_cli/util.rb
index 98c3002..d12c5a6 100644
--- a/lib/leap_cli/util.rb
+++ b/lib/leap_cli/util.rb
@@ -28,9 +28,9 @@ module LeapCli
LeapCli.log_level = 3
yield
elsif message
- puts message
+ log 0, message
end
- log :bail, ""
+ log 0, :bail, ""
raise SystemExit.new
end
@@ -105,11 +105,11 @@ module LeapCli
def assert_config!(conf_path)
value = nil
- begin
+ #begin
value = manager.instance_eval(conf_path)
- rescue NoMethodError
- rescue NameError
- end
+ #rescue NoMethodError
+ #rescue NameError
+ #end
assert! !value.nil? && value != "REQUIRED" do
log :missing, "required configuration value for #{conf_path}"
end
@@ -199,19 +199,39 @@ module LeapCli
def remove_file!(filepath)
filepath = Path.named_path(filepath)
if File.exists?(filepath)
- File.unlink(filepath)
- log :removed, filepath
+ if File.directory?(filepath)
+ remove_directory!(filepath)
+ else
+ begin
+ File.unlink(filepath)
+ log :removed, filepath
+ rescue Exception => exc
+ bail! do
+ log :failed, "to remove file #{filepath}"
+ log "error message: " + exc.to_s
+ end
+ end
+ end
end
end
def remove_directory!(filepath)
filepath = Path.named_path(filepath)
if filepath !~ /^#{Regexp.escape(Path.provider)}/ || filepath =~ /\.\./
- raise "sanity check on rm -r did not pass for #{filepath}"
+ bail! "sanity check on rm -r did not pass for #{filepath}"
end
if File.directory?(filepath)
- FileUtils.rm_r(filepath)
- log :removed, filepath
+ begin
+ FileUtils.rm_r(filepath)
+ log :removed, filepath
+ rescue Exception => exc
+ bail! do
+ log :failed, "to remove directory #{filepath}"
+ log "error message: " + exc.to_s
+ end
+ end
+ else
+ log :failed, "to remove '#{filepath}', it is not a directory"
end
end
@@ -237,6 +257,21 @@ module LeapCli
end
end
+ def rename_file!(oldpath, newpath)
+ oldpath = Path.named_path(oldpath)
+ newpath = Path.named_path(newpath)
+ if File.exists? newpath
+ log :skipping, "#{Path.relative_path(newpath)}, file already exists"
+ return
+ end
+ if !File.exists? oldpath
+ log :skipping, "#{Path.relative_path(oldpath)}, file is missing"
+ return
+ end
+ FileUtils.mv oldpath, newpath
+ log :moved, "#{Path.relative_path(oldpath)} to #{Path.relative_path(newpath)}"
+ end
+
def cmd_exists?(cmd)
`which #{cmd}`.strip.chars.any?
end