lib/bosh-bootstrap/cli.rb in bosh-bootstrap-0.7.1 vs lib/bosh-bootstrap/cli.rb in bosh-bootstrap-0.8.0
- old
+ new
@@ -21,17 +21,17 @@
attr_reader :fog_credentials
attr_reader :server
desc "deploy", "Bootstrap Micro BOSH, and optionally an Inception VM"
method_option :fog, :type => :string, :desc => "fog config file (default: ~/.fog)"
- method_option :"private-key", :type => :string, :desc => "Local passphrase-less private key path"
method_option :"upgrade-deps", :type => :boolean, :desc => "Force upgrade dependencies, packages & gems"
method_option :"edge-deployer", :type => :boolean, :desc => "Install bosh deployer from git instead of rubygems"
method_option :"stable-stemcell", :type => :boolean, :desc => "Use recent stable microbosh stemcell"
method_option :"latest-stemcell", :type => :boolean, :desc => "Use latest microbosh stemcell; possibly not tagged stable [default]"
method_option :"edge-stemcell", :type => :boolean, :desc => "Create custom stemcell from BOSH git source"
def deploy
+ migrate_old_settings
load_deploy_options # from method_options above
deploy_stage_1_choose_infrastructure_provider
deploy_stage_2_bosh_configuration
deploy_stage_3_create_allocate_inception_vm
@@ -41,10 +41,11 @@
end
desc "upgrade-inception", "Upgrade inception VM with latest packages, gems, security group ports"
method_option :"edge-deployer", :type => :boolean, :desc => "Install bosh deployer from git instead of rubygems"
def upgrade_inception
+ migrate_old_settings
load_deploy_options # from method_options above
setup_server
upgrade_inception_stage_1_prepare_inception_vm
end
@@ -67,28 +68,31 @@
long_desc <<-DESC
If a command is supplied, it will be run, otherwise a session will be
opened.
DESC
def ssh(cmd=nil)
+ migrate_old_settings
run_ssh_command_or_open_tunnel(cmd)
end
desc "tmux", "Open an ssh (with tmux) session to the inception VM [do nothing if local machine is inception VM]"
long_desc <<-DESC
Opens a connection using ssh and attaches to the most recent tmux session;
giving you persistance across disconnects.
DESC
def tmux
+ migrate_old_settings
run_ssh_command_or_open_tunnel(["-t", "tmux attach || tmux new-session"])
end
desc "mosh", "Open an mosh session to the inception VM [do nothing if local machine is inception VM]"
long_desc <<-DESC
Opens a connection using MOSH (http://mosh.mit.edu/); ideal for those with slow or flakey internet connections.
Requires outgoing UDP port 60001 to the Inception VM
DESC
def mosh
+ migrate_old_settings
open_mosh_session
end
no_tasks do
DEFAULT_INCEPTION_VOLUME_SIZE = 32 # Gb
@@ -232,10 +236,14 @@
end
end
save_settings!
if settings["inception"]["create_new"] && !settings["inception"]["host"]
+ unless settings["inception"]["key_pair"]
+ create_inception_key_pair
+ end
+ recreate_local_ssh_keys_for_inception_vm
aws? ? boot_aws_inception_vm : boot_openstack_inception_vm
end
# If successfully validate inception VM, then save those settings.
save_settings!
@@ -252,10 +260,12 @@
end
def deploy_stage_4_prepare_inception_vm
unless settings["inception"] && settings["inception"]["prepared"] && !settings["upgrade_deps"]
header "Stage 4: Preparing the Inception VM"
+ recreate_local_ssh_keys_for_inception_vm
+
unless run_server(Bosh::Bootstrap::Stages::StagePrepareInceptionVm.new(settings).commands)
error "Failed to complete Stage 4: Preparing the Inception VM"
end
# Settings are updated by this stage
# it generates a salted password from settings.bosh.password
@@ -267,10 +277,12 @@
end
end
def deploy_stage_5_deploy_micro_bosh
header "Stage 5: Deploying micro BOSH"
+ recreate_local_ssh_keys_for_inception_vm
+
unless run_server(Bosh::Bootstrap::Stages::MicroBoshDeploy.new(settings).commands)
error "Failed to complete Stage 5: Deploying micro BOSH"
end
confirm "Successfully built micro BOSH"
@@ -327,11 +339,12 @@
end
def setup_server
if settings["inception"]["host"]
- @server = Commander::RemoteServer.new(settings.inception.host, settings.local.private_key_path)
+ private_key_path = settings["inception"]["local_private_key_path"]
+ @server = Commander::RemoteServer.new(settings.inception.host, private_key_path)
confirm "Using inception VM #{settings.inception.username}@#{settings.inception.host}"
else
@server = Commander::LocalServer.new
confirm "Using this server as the inception VM"
end
@@ -356,15 +369,15 @@
end
def run_ssh_command_or_open_tunnel(cmd)
ensure_inception_vm
ensure_inception_vm_has_launched
+ recreate_local_ssh_keys_for_inception_vm
- username = 'vcap'
- host = settings.inception[:host]
- _, private_key_path = local_ssh_key_paths
- result = system Escape.shell_command(['ssh', "-i", "#{private_key_path}", "#{username}@#{host}", cmd].flatten.compact)
+ username = "vcap"
+ host = settings["inception"]["host"]
+ result = system Escape.shell_command(["ssh", "-i", inception_vm_private_key_path, "#{username}@#{host}", cmd].flatten.compact)
exit result
end
def ensure_inception_vm
unless settings[:inception]
@@ -380,10 +393,11 @@
def open_mosh_session
ensure_mosh_installed
ensure_inception_vm
ensure_inception_vm_has_launched
+ recreate_local_ssh_keys_for_inception_vm
ensure_security_group_allows_mosh
username = 'vcap'
host = settings.inception[:host]
exit system Escape.shell_command(['mosh', "#{username}@#{host}"])
@@ -470,25 +484,10 @@
# once a stemcell is downloaded or created; these fields above should
# be uploaded with values such as:
# -> settings["micro_bosh_stemcell_name"] = "micro-bosh-stemcell-aws-0.8.1.tgz"
- if options["private-key"]
- private_key_path = File.expand_path(options["private-key"])
- unless File.exists?(private_key_path)
- error "Cannot find a file at #{private_key_path}"
- end
- public_key_path = "#{private_key_path}.pub"
- unless File.exists?(public_key_path)
- error "Cannot find a file at #{public_key_path}"
- end
-
- settings["local"] ||= {}
- settings["local"]["private_key_path"] = private_key_path
- settings["local"]["public_key_path"] = public_key_path
- end
-
if options["upgrade-deps"]
settings["upgrade_deps"] = options["upgrade-deps"]
else
settings.delete("upgrade_deps")
end
@@ -804,36 +803,75 @@
else
error "Key pair '#{key_pair_name}' already exists. Rename BOSH or delete old key pair manually and re-run CLI."
end
end
+ # Creates a key pair with the provider for the inception VM.
+ # Stores the private & public key in settings manifest.
+ #
+ # If provider already has a key pair of the same name, it re-creates it.
+ #
+ # Adds settings:
+ # * inception.key_pair.name
+ # * inception.key_pair.public_key
+ # * inception.key_pair.private_key
+ # * inception.key_pair.fingerprint
+ def create_inception_key_pair
+ say "Creating ssh key pair for Inception VM..."
+ create_key_pair_store_in_settings("inception")
+ end
+
+ # Creates a key pair with the provider.
+ # Stores the private & public key in settings manifest.
+ #
+ # If provider already has a key pair of the same name, it re-creates it.
+ #
+ # Adds settings:
+ # * <settings_key>.key_pair.name # defaults to settings_key value
+ # * <settings_key>.key_pair.public_key
+ # * <settings_key>.key_pair.private_key
+ # * <settings_key>.key_pair.fingerprint
+ def create_key_pair_store_in_settings(settings_key, default_key_pair_name = settings_key)
+ settings[settings_key] ||= {}
+ settings[settings_key]["key_pair"] ||= {}
+ key_pair_settings = settings[settings_key]["key_pair"]
+ key_pair_settings["name"] ||= default_key_pair_name
+ key_pair_name = key_pair_settings["name"]
+
+ provider.delete_key_pair_if_exists(key_pair_name)
+ fog_key_pair = provider.create_key_pair(key_pair_name)
+
+ key_pair_settings["private_key"] = fog_key_pair.private_key
+ key_pair_settings["public_key"] = fog_key_pair.public_key
+ key_pair_settings["fingerprint"] = fog_key_pair.fingerprint
+ save_settings!
+ end
+
# Provisions an AWS m1.small VM as the inception VM
# Updates settings.inception.host/username
#
# NOTE: if any stage fails, when the CLI is re-run
# and "create new server" is selected again, the process should
# complete
- #
- # Assumes that local CLI user has public/private keys at ~/.ssh/id_rsa.pub
def boot_aws_inception_vm
say "" # glowing whitespace
unless settings["inception"]["ip_address"]
say "Provisioning IP address for inception VM..."
settings["inception"]["ip_address"] = acquire_ip_address
save_settings!
end
- public_key_path, private_key_path = local_ssh_key_paths
unless settings["inception"] && settings["inception"]["server_id"]
username = "ubuntu"
size = "m1.small"
ip_address = settings["inception"]["ip_address"]
+ key_name = settings["inception"]["key_pair"]["name"]
say "Provisioning #{size} for inception VM..."
inception_vm_attributes = {
- :public_key_path => public_key_path,
- :private_key_path => private_key_path,
+ :key_name => key_name,
+ :private_key_path => inception_vm_private_key_path,
:flavor_id => size,
:bits => 64,
:username => "ubuntu",
:public_ip_address => ip_address
}
@@ -845,11 +883,11 @@
server = provider.bootstrap(inception_vm_attributes)
unless server
error "Something mysteriously cloudy happened and fog could not provision a VM. Please check your limits."
end
- settings["inception"] = {}
+ settings["inception"].delete("create_new")
settings["inception"]["server_id"] = server.id
settings["inception"]["username"] = username
save_settings!
end
@@ -883,29 +921,13 @@
# Updates settings.inception.host/username
#
# NOTE: if any stage fails, when the CLI is re-run
# and "create new server" is selected again, the process should
# complete
- #
- # Assumes that local CLI user has public/private keys at ~/.ssh/id_rsa.pub
def boot_openstack_inception_vm
say "" # glowing whitespace
- public_key_path, private_key_path = local_ssh_key_paths
-
- # make sure we've a fog key pair
- key_pair_name = Fog.respond_to?(:credential) && Fog.credential || :default
- unless key_pair = fog_compute.key_pairs.get("fog_#{key_pair_name}")
- say "creating key pair fog_#{key_pair_name}..."
- public_key = File.open(public_key_path, 'rb') { |f| f.read }
- key_pair = fog_compute.key_pairs.create(
- :name => "fog_#{key_pair_name}",
- :public_key => public_key
- )
- end
- confirm "Using key pair #{key_pair.name} for Inception VM"
-
unless settings["inception"] && settings["inception"]["server_id"]
username = "ubuntu"
say "Provisioning server for inception VM..."
settings["inception"] ||= {}
@@ -949,16 +971,16 @@
end
end
say ""
confirm "Using image #{inception_image.name} for Inception VM"
+ key_name = settings["inception"]["key_pair"]["name"]
+
# Boot OpenStack server
server = fog_compute.servers.create(
:name => "Inception VM",
- :key_name => key_pair.name,
- :public_key_path => public_key_path,
- :private_key_path => private_key_path,
+ :key_name => key_name,
:flavor_ref => inception_flavor.id,
:image_ref => inception_image.id,
:username => username
)
unless server
@@ -1072,33 +1094,40 @@
end
end
end
def display_inception_ssh_access
- _, private_key_path = local_ssh_key_paths
- say "SSH access: ssh -i #{private_key_path} #{settings["inception"]["username"]}@#{settings["inception"]["host"]}"
+ say "SSH access: ssh -i #{inception_vm_private_key_path} #{settings["inception"]["username"]}@#{settings["inception"]["host"]}"
end
def run_server(server_commands)
server.run(server_commands)
end
- # Discover/create local passphrase-less SSH keys to allow
- # communication with Inception VM
- #
- # Returns [public_key_path, private_key_path]
- def local_ssh_key_paths
- unless settings["local"] && settings["local"]["private_key_path"]
- settings["local"] = {}
- public_key_path = File.expand_path("~/.ssh/id_rsa.pub")
- private_key_path = File.expand_path("~/.ssh/id_rsa")
- raise "Please create public keys at ~/.ssh/id_rsa.pub or use --private-key flag" unless File.exists?(public_key_path)
-
- settings["local"]["public_key_path"] = public_key_path
- settings["local"]["private_key_path"] = private_key_path
+ def inception_vm_private_key_path
+ unless settings["inception"] && settings["inception"]["local_private_key_path"]
+ settings["inception"] ||= {}
+ settings["inception"]["local_private_key_path"] = File.join(settings_ssh_dir, "inception")
save_settings!
end
- [settings.local.public_key_path, settings.local.private_key_path]
+ settings["inception"]["local_private_key_path"]
+ end
+
+ # The keys for the inception VM originate from the provider and are cached in
+ # the manifest. The private key is stored locally; the public key is placed
+ # on the inception VM.
+ def recreate_local_ssh_keys_for_inception_vm
+ unless settings["inception"] && (key_pair = settings["inception"]["key_pair"])
+ raise "please run create_inception_key_pair first"
+ end
+ private_key_contents = key_pair["private_key"]
+ unless File.exist?(inception_vm_private_key_path) && File.read(inception_vm_private_key_path) == private_key_contents
+ say "Creating missing inception VM private key..."
+ mkdir_p(File.dirname(inception_vm_private_key_path))
+ File.chmod(0700, File.dirname(inception_vm_private_key_path))
+ File.open(inception_vm_private_key_path, "w") { |file| file << private_key_contents }
+ File.chmod(0600, inception_vm_private_key_path)
+ end
end
def aws?
settings.fog_credentials.provider == "AWS"
end