diff options
Diffstat (limited to 'lib/leap_cli/commands/deploy.rb')
-rw-r--r-- | lib/leap_cli/commands/deploy.rb | 163 |
1 files changed, 135 insertions, 28 deletions
diff --git a/lib/leap_cli/commands/deploy.rb b/lib/leap_cli/commands/deploy.rb index 814407f..6589837 100644 --- a/lib/leap_cli/commands/deploy.rb +++ b/lib/leap_cli/commands/deploy.rb @@ -17,9 +17,12 @@ module LeapCli # --force c.switch :force, :desc => 'Deploy even if there is a lockfile.', :negatable => false + # --dev + c.switch :dev, :desc => "Development mode: don't run 'git submodule update' before deploy.", :negatable => false + # --tags c.flag :tags, :desc => 'Specify tags to pass through to puppet (overriding the default).', - :default_value => DEFAULT_TAGS.join(','), :arg_name => 'TAG[,TAG]' + :arg_name => 'TAG[,TAG]' c.flag :port, :desc => 'Override the default SSH port.', :arg_name => 'PORT' @@ -28,9 +31,12 @@ module LeapCli :arg_name => 'IPADDRESS' c.action do |global,options,args| - init_submodules - nodes = filter_deploy_nodes(args) + if options[:dev] != true + init_submodules + end + + nodes = manager.filter!(args) if nodes.size > 1 say "Deploying to these nodes: #{nodes.keys.join(', ')}" if !global[:yes] && !agree("Continue? ") @@ -38,7 +44,16 @@ module LeapCli end end - compile_hiera_files + environments = nodes.field('environment').uniq + if environments.empty? + environments = [nil] + end + environments.each do |env| + check_platform_pinning(env) + end + # compile hiera files for all the nodes in every environment that is + # being deployed and only those environments. + compile_hiera_files(manager.filter(environments)) ssh_connect(nodes, connect_options(options)) do |ssh| ssh.leap.log :checking, 'node' do @@ -58,39 +73,128 @@ module LeapCli end end end + end end private + # + # The currently activated provider.json could have loaded some pinning + # information for the platform. If this is the case, refuse to deploy + # if there is a mismatch. + # + # For example: + # + # "platform": { + # "branch": "develop" + # "version": "1.0..99" + # "commit": "e1d6280e0a8c565b7fb1a4ed3969ea6fea31a5e2..HEAD" + # } + # + def check_platform_pinning(environment) + provider = manager.env(environment).provider + return unless provider['platform'] + + if environment.nil? || environment == 'default' + provider_json = 'provider.json' + else + provider_json = 'provider.' + environment + '.json' + end + + # can we have json schema verification already? + unless provider.platform.is_a? Hash + bail!('`platform` attribute in #{provider_json} must be a hash (was %s).' % provider.platform.inspect) + end + + # check version + if provider.platform['version'] + if !Leap::Platform.version_in_range?(provider.platform.version) + say("The platform is pinned to a version range of '#{provider.platform.version}' "+ + "by the `platform.version` property in #{provider_json}, but the platform "+ + "(#{Path.platform}) has version #{Leap::Platform.version}.") + quit!("OK. Bye.") unless agree("Do you really want to deploy from the wrong version? ") + end + end + + # check branch + if provider.platform['branch'] + if !is_git_directory?(Path.platform) + say("The platform is pinned to a particular branch by the `platform.branch` property "+ + "in #{provider_json}, but the platform directory (#{Path.platform}) is not a git repository.") + quit!("OK. Bye.") unless agree("Do you really want to deploy anyway? ") + end + unless provider.platform.branch == current_git_branch(Path.platform) + say("The platform is pinned to branch '#{provider.platform.branch}' by the `platform.branch` property "+ + "in #{provider_json}, but the current branch is '#{current_git_branch(Path.platform)}' " + + "(for directory '#{Path.platform}')") + quit!("OK. Bye.") unless agree("Do you really want to deploy from the wrong branch? ") + end + end + + # check commit + if provider.platform['commit'] + if !is_git_directory?(Path.platform) + say("The platform is pinned to a particular commit range by the `platform.commit` property "+ + "in #{provider_json}, but the platform directory (#{Path.platform}) is not a git repository.") + quit!("OK. Bye.") unless agree("Do you really want to deploy anyway? ") + end + current_commit = current_git_commit(Path.platform) + Dir.chdir(Path.platform) do + commit_range = assert_run!("git log --pretty='format:%H' '#{provider.platform.commit}'", + "The platform is pinned to a particular commit range by the `platform.commit` property "+ + "in #{provider_json}, but git was not able to find commits in the range specified "+ + "(#{provider.platform.commit}).") + commit_range = commit_range.split("\n") + if !commit_range.include?(current_commit) && + provider.platform.commit.split('..').first != current_commit + say("The platform is pinned via the `platform.commit` property in #{provider_json} " + + "to a commit in the range #{provider.platform.commit}, but the current HEAD " + + "(#{current_commit}) is not in that range.") + quit!("OK. Bye.") unless agree("Do you really want to deploy from the wrong commit? ") + end + end + end + end + def sync_hiera_config(ssh) - dest_dir = provider.hiera_sync_destination ssh.rsync.update do |server| node = manager.node(server.host) hiera_file = Path.relative_path([:hiera, node.name]) - ssh.leap.log hiera_file + ' -> ' + node.name + ':' + dest_dir + '/hiera.yaml' + ssh.leap.log hiera_file + ' -> ' + node.name + ':' + Leap::Platform.hiera_path { :source => hiera_file, - :dest => dest_dir + '/hiera.yaml', + :dest => Leap::Platform.hiera_path, :flags => "-rltp --chmod=u+rX,go-rwx" } end end + # + # sync various support files. + # def sync_support_files(ssh) - dest_dir = provider.hiera_sync_destination + dest_dir = Leap::Platform.files_dir + source_files = [] + if Path.defined?(:custom_puppet_dir) && file_exists?(:custom_puppet_dir) + source_files += [:custom_puppet_dir, :custom_puppet_modules_dir, :custom_puppet_manifests_dir].collect{|path| + Path.relative_path(path, Path.provider) + '/' # rsync needs trailing slash + } + ensure_dir :custom_puppet_modules_dir + end ssh.rsync.update do |server| node = manager.node(server.host) files_to_sync = node.file_paths.collect {|path| Path.relative_path(path, Path.provider) } + files_to_sync += source_files if files_to_sync.any? ssh.leap.log(files_to_sync.join(', ') + ' -> ' + node.name + ':' + dest_dir) { - :chdir => Path.provider, + :chdir => Path.named_path(:files_dir), :source => ".", :dest => dest_dir, :excludes => "*", - :includes => calculate_includes_from_files(files_to_sync), - :flags => "-rltp --chmod=u+rX,go-rwx --relative --delete --delete-excluded --filter='protect hiera.yaml' --copy-links" + :includes => calculate_includes_from_files(files_to_sync, '/files'), + :flags => "-rltp --chmod=u+rX,go-rwx --relative --delete --delete-excluded --copy-links" } else nil @@ -100,9 +204,9 @@ module LeapCli def sync_puppet_files(ssh) ssh.rsync.update do |server| - ssh.leap.log(Path.platform + '/[bin,tests,puppet] -> ' + server.host + ':' + LeapCli::PUPPET_DESTINATION) + ssh.leap.log(Path.platform + '/[bin,tests,puppet] -> ' + server.host + ':' + Leap::Platform.leap_dir) { - :dest => LeapCli::PUPPET_DESTINATION, + :dest => Leap::Platform.leap_dir, :source => '.', :chdir => Path.platform, :excludes => '*', @@ -112,7 +216,12 @@ module LeapCli end end + # + # ensure submodules are up to date, if the platform is a git + # repository. + # def init_submodules + return unless is_git_directory?(Path.platform) Dir.chdir Path.platform do assert_run! "git submodule sync" statuses = assert_run! "git submodule status" @@ -126,11 +235,17 @@ module LeapCli end end - def calculate_includes_from_files(files) + # + # converts an array of file paths into an array + # suitable for --include of rsync + # + # if set, `prefix` is stripped off. + # + def calculate_includes_from_files(files, prefix=nil) return nil unless files and files.any? # prepend '/' (kind of like ^ for rsync) - includes = files.collect {|file| '/' + file} + includes = files.collect {|file| file =~ /^\// ? file : '/' + file } # include all sub files of specified directories includes.size.times do |i| @@ -148,6 +263,10 @@ module LeapCli end end + if prefix + includes.map! {|path| path.sub(/^#{Regexp.escape(prefix)}\//, '/')} + end + return includes end @@ -155,23 +274,11 @@ module LeapCli if options[:tags] tags = options[:tags].split(',') else - tags = LeapCli::DEFAULT_TAGS.dup + tags = Leap::Platform.default_puppet_tags.dup end tags << 'leap_slow' unless options[:fast] tags.join(',') end - # - # for safety, we allow production deploys to be turned off in the Leapfile. - # - def filter_deploy_nodes(filter) - nodes = manager.filter!(filter) - if !leapfile.allow_production_deploy - nodes = nodes[:environment => "!production"] - assert! nodes.any?, "Skipping deploy because @allow_production_deploy is disabled." - end - nodes - end - end end |