Merge branch 'CID-410-named_tasks' into features
This commit is contained in:
		
						commit
						b8bdb7806b
					
				| @ -25,7 +25,12 @@ class Deploy < Handler | |||||||
|       @options_parser.invalid_deploy_command |       @options_parser.invalid_deploy_command | ||||||
|       abort() |       abort() | ||||||
|     end |     end | ||||||
|     job_ids = post("/deploy", names: names, tags: options[:tags], chef_client_options: options[:chef_client_options]) |     job_ids = post("/deploy", | ||||||
|  |       names: names, | ||||||
|  |       tags: options[:tags], | ||||||
|  |       chef_client_options: options[:chef_client_options], | ||||||
|  |       named_task: options[:named_task] | ||||||
|  |     ) | ||||||
|     reports_urls(job_ids) |     reports_urls(job_ids) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ class DeployOptions < CommonOptions | |||||||
|         options[:tags] = tags.split(",") |         options[:tags] = tags.split(",") | ||||||
|       end |       end | ||||||
|       parser.recognize_option_value(:chef_client_options) |       parser.recognize_option_value(:chef_client_options) | ||||||
| 
 |       parser.recognize_option_value(:named_task) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -315,6 +315,7 @@ en: | |||||||
|       deploy: |       deploy: | ||||||
|         tag: 'Tag names, comma separated list' |         tag: 'Tag names, comma separated list' | ||||||
|         chef_client_options: 'String like "-o role[foo]"' |         chef_client_options: 'String like "-o role[foo]"' | ||||||
|  |         named_task: Name of task to run | ||||||
|       image: |       image: | ||||||
|         provider: Image provider |         provider: Image provider | ||||||
|         image_id: Image identifier |         image_id: Image identifier | ||||||
|  | |||||||
| @ -19,7 +19,6 @@ module Devops | |||||||
|           names = body["names"] |           names = body["names"] | ||||||
|           tags = body["tags"] || [] |           tags = body["tags"] || [] | ||||||
|           run_list = body["run_list"] |           run_list = body["run_list"] | ||||||
|           single_run_chef_client_options = body['chef_client_options'] |  | ||||||
|           files = [] |           files = [] | ||||||
|           jid = nil |           jid = nil | ||||||
|           owner = parser.current_user |           owner = parser.current_user | ||||||
| @ -34,7 +33,8 @@ module Devops | |||||||
|             begin |             begin | ||||||
|               deploy_info = create_deploy_info(s, project, body["build_number"]) |               deploy_info = create_deploy_info(s, project, body["build_number"]) | ||||||
|               deploy_info["run_list"] = run_list if run_list |               deploy_info["run_list"] = run_list if run_list | ||||||
|               set_chef_client_options(deploy_info, s, project, single_run_chef_client_options) |               set_chef_client_options(deploy_info, s, project, body['chef_client_options']) | ||||||
|  |               deploy_info["named_task"] = body["named_task"] | ||||||
| 
 | 
 | ||||||
|               jid = Worker.start_async(DeployWorker, |               jid = Worker.start_async(DeployWorker, | ||||||
|                 server_attrs: s.to_hash, |                 server_attrs: s.to_hash, | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ require "app/api2/parsers/project" | |||||||
| require "lib/project/type/types_factory" | require "lib/project/type/types_factory" | ||||||
| require "lib/executors/server_executor" | require "lib/executors/server_executor" | ||||||
| require "workers/delete_server_worker" | require "workers/delete_server_worker" | ||||||
| 
 |  | ||||||
| require_relative "../helpers/version_2.rb" | require_relative "../helpers/version_2.rb" | ||||||
| require_relative "request_handler" | require_relative "request_handler" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ module Devops | |||||||
|           build_number = check_string(r["build_number"], "Parameter 'build_number' should be a not empty string", true) |           build_number = check_string(r["build_number"], "Parameter 'build_number' should be a not empty string", true) | ||||||
|           rl = check_array(r["run_list"], "Parameter 'run_list' should be an array of string", String, true) |           rl = check_array(r["run_list"], "Parameter 'run_list' should be an array of string", String, true) | ||||||
|           Validators::Helpers::RunList.new(rl).validate! unless rl.nil? |           Validators::Helpers::RunList.new(rl).validate! unless rl.nil? | ||||||
|  |           check_string(r["named_task"], "Parameter 'named_task' should be a not empty string", true) | ||||||
|           r |           r | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -87,28 +87,12 @@ module Devops | |||||||
|           #     - Content-Type: application/json |           #     - Content-Type: application/json | ||||||
|           #   - body : |           #   - body : | ||||||
|           #     { |           #     { | ||||||
|           #       "deploy_envs": [ |           #       "run_list": [], | ||||||
|           #         { |           #       "description": "Description", | ||||||
|           #           "identifier": "dev", |           #       "named_tasks": [{ | ||||||
|           #           "provider": "openstack", |           #         "name": "restart", | ||||||
|           #           "flavor": "m1.small", |           #         "run_list": ["role[restart_service]"] | ||||||
|           #           "image": "image id", |           #       }] | ||||||
|           #           "subnets": [ |  | ||||||
|           #             "private" |  | ||||||
|           #           ], |  | ||||||
|           #           "groups": [ |  | ||||||
|           #             "default" |  | ||||||
|           #           ], |  | ||||||
|           #           "users": [ |  | ||||||
|           #             "user" |  | ||||||
|           #           ], |  | ||||||
|           #           "run_list": [ |  | ||||||
|           # |  | ||||||
|           #           ], |  | ||||||
|           #           "expires": null |  | ||||||
|           #         } |  | ||||||
|           #       ], |  | ||||||
|           #       "name": "project_1" |  | ||||||
|           #     } |           #     } | ||||||
|           # |           # | ||||||
|           # * *Returns* : |           # * *Returns* : | ||||||
|  | |||||||
| @ -135,13 +135,16 @@ module Connectors | |||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def project_update id, params |     def project_update id, params | ||||||
|       keys = %w(run_list description) |       params.keep_if {|k,v| permitted_project_fields.include?(k)} | ||||||
|       params.delete_if{|k,v| !keys.include?(k)} |  | ||||||
|       @collection.update({"_id" => id}, {'$set' => params }) |       @collection.update({"_id" => id}, {'$set' => params }) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private |     private | ||||||
| 
 | 
 | ||||||
|  |     def permitted_project_fields | ||||||
|  |       %w(run_list description named_tasks) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     def list(query={}, query_options={}) |     def list(query={}, query_options={}) | ||||||
|       @collection.find(query, query_options).to_a.map {|bson| model_from_bson(bson)} |       @collection.find(query, query_options).to_a.map {|bson| model_from_bson(bson)} | ||||||
|     end |     end | ||||||
|  | |||||||
| @ -41,12 +41,23 @@ module Devops | |||||||
|                                       ::Validators::FieldValidator::FieldType::Array, |                                       ::Validators::FieldValidator::FieldType::Array, | ||||||
|                                       ::Validators::FieldValidator::RunList] |                                       ::Validators::FieldValidator::RunList] | ||||||
| 
 | 
 | ||||||
|  |       # should be an array of hashes like: | ||||||
|  |       # { | ||||||
|  |       #   'name' => 'restart', | ||||||
|  |       #   'run_list' => [ | ||||||
|  |       #     'role[restart_service]' | ||||||
|  |       #   ] | ||||||
|  |       # } | ||||||
|  |       set_field_validators :named_tasks, [::Validators::FieldValidator::Nil, | ||||||
|  |                                     ::Validators::FieldValidator::FieldType::Array, | ||||||
|  |                                     ::Validators::FieldValidator::NamedTasks] | ||||||
|  | 
 | ||||||
|       set_validators ::Validators::DeployEnv::RunList, |       set_validators ::Validators::DeployEnv::RunList, | ||||||
|                      ::Validators::DeployEnv::DeployEnvs |                      ::Validators::DeployEnv::DeployEnvs | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|       def self.fields |       def self.fields | ||||||
|         ["deploy_envs", "type", "description"] |         ["deploy_envs", "type", "description", "named_tasks"] | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def initialize p={} |       def initialize p={} | ||||||
| @ -56,6 +67,7 @@ module Devops | |||||||
|         self.description = p["description"] |         self.description = p["description"] | ||||||
|         self.archived = p["archived"] || false |         self.archived = p["archived"] || false | ||||||
|         self.run_list = p["run_list"] || [] |         self.run_list = p["run_list"] || [] | ||||||
|  |         self.named_tasks = p["named_tasks"] || [] | ||||||
| 
 | 
 | ||||||
|         @handler = Devops::TypesFactory.type self.type |         @handler = Devops::TypesFactory.type self.type | ||||||
|         @handler.prepare(self) |         @handler.prepare(self) | ||||||
| @ -174,6 +186,7 @@ module Devops | |||||||
|         h["archived"] = self.archived if self.archived |         h["archived"] = self.archived if self.archived | ||||||
|         h["description"] = self.description |         h["description"] = self.description | ||||||
|         h["run_list"] = self.run_list |         h["run_list"] = self.run_list | ||||||
|  |         h["named_tasks"] = self.named_tasks | ||||||
|         if self.multi? |         if self.multi? | ||||||
|           h["type"] = MULTI_TYPE |           h["type"] = MULTI_TYPE | ||||||
|         end |         end | ||||||
|  | |||||||
							
								
								
									
										65
									
								
								devops-service/db/validators/field_validators/named_tasks.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								devops-service/db/validators/field_validators/named_tasks.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | require_relative "base" | ||||||
|  | 
 | ||||||
|  | module Validators | ||||||
|  |   module FieldValidator | ||||||
|  |     class NamedTasks < Base | ||||||
|  | 
 | ||||||
|  |       def valid? | ||||||
|  |         @value.each do |named_task| | ||||||
|  |           break unless check_name!(named_task) | ||||||
|  |           break unless check_run_list!(named_task) | ||||||
|  |           break unless check_additional_keys!(named_task) | ||||||
|  |         end | ||||||
|  |         @message.nil? | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def message | ||||||
|  |         @message | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       private | ||||||
|  | 
 | ||||||
|  |       def check_name!(task) | ||||||
|  |         if task.key?('name') | ||||||
|  |           true | ||||||
|  |         else | ||||||
|  |           @message = "One of tasks doesn't have a name" | ||||||
|  |           false | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def check_run_list!(task) | ||||||
|  |         if !task.key?('run_list') | ||||||
|  |           @message = "Task #{task['name']} doesn't have run_list" | ||||||
|  |           return false | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         if !task['run_list'].is_a?(Array) | ||||||
|  |           @message = "Run list of #{task['name']} isn't an array" | ||||||
|  |           return false | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         wrong_elements = task['run_list'].select do |element| | ||||||
|  |           Validators::Helpers::RunList::RUN_LIST_REGEX.match(element).nil? | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         if wrong_elements.empty? | ||||||
|  |           true | ||||||
|  |         else | ||||||
|  |           @message = "Invalid run list elements: '#{wrong_elements.join(', ')}' for task #{task['name']}." | ||||||
|  |           false | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def check_additional_keys!(task) | ||||||
|  |         if task.keys.length > 2 | ||||||
|  |           @message = "Task hash should contain only name and run_list" | ||||||
|  |           false | ||||||
|  |         else | ||||||
|  |           true | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -1,5 +1,6 @@ | |||||||
| require "lib/knife/knife_factory" | require "lib/knife/knife_factory" | ||||||
| require "lib/executors/expiration_scheduler" | require "lib/executors/expiration_scheduler" | ||||||
|  | require "lib/puts_and_flush" | ||||||
| require "hooks" | require "hooks" | ||||||
| require 'net/ssh' | require 'net/ssh' | ||||||
| 
 | 
 | ||||||
| @ -7,6 +8,7 @@ module Devops | |||||||
|   module Executor |   module Executor | ||||||
|     class ServerExecutor |     class ServerExecutor | ||||||
|       include Hooks |       include Hooks | ||||||
|  |       include PutsAndFlush | ||||||
| 
 | 
 | ||||||
|       ERROR_CODES = { |       ERROR_CODES = { | ||||||
|         server_bootstrap_fail: 2, |         server_bootstrap_fail: 2, | ||||||
| @ -41,6 +43,7 @@ module Devops | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|       attr_accessor :server, :deploy_env, :report, :project |       attr_accessor :server, :deploy_env, :report, :project | ||||||
|  |       attr_reader :out | ||||||
| 
 | 
 | ||||||
|       def initialize server, out, options={} |       def initialize server, out, options={} | ||||||
|         if server |         if server | ||||||
| @ -394,9 +397,13 @@ module Devops | |||||||
|           @out.flush |           @out.flush | ||||||
|           cmd << " -j http://#{DevopsConfig.config[:address]}:#{DevopsConfig.config[:port]}/#{DevopsConfig.config[:url_prefix]}/v2.0/deploy/data/#{file}" |           cmd << " -j http://#{DevopsConfig.config[:address]}:#{DevopsConfig.config[:port]}/#{DevopsConfig.config[:url_prefix]}/v2.0/deploy/data/#{file}" | ||||||
|         else |         else | ||||||
|           chef_client_options = deploy_info['chef_client_options'] |           if deploy_info['chef_client_options'].present? | ||||||
|           if chef_client_options && !chef_client_options.empty? |             cmd << " #{deploy_info['chef_client_options']}" | ||||||
|             cmd << " #{chef_client_options}" |           elsif deploy_info['named_task'].present? | ||||||
|  |             named_task = @project.named_tasks.detect {|task| task['name'] == deploy_info['named_task']} | ||||||
|  |             raise "Named task #{deploy_info['named_task']} doesn't exist." unless named_task | ||||||
|  |             puts_and_flush "Using named task #{deploy_info['named_task']}." | ||||||
|  |             cmd << " -o #{named_task['run_list'].join(',')}" | ||||||
|           else |           else | ||||||
|             cmd << " -r #{deploy_info["run_list"].join(",")}" unless @server.stack.nil? |             cmd << " -r #{deploy_info["run_list"].join(",")}" unless @server.stack.nil? | ||||||
|           end |           end | ||||||
| @ -504,11 +511,6 @@ module Devops | |||||||
| 
 | 
 | ||||||
|       private |       private | ||||||
| 
 | 
 | ||||||
|       def puts_and_flush(message) |  | ||||||
|         @out.puts message |  | ||||||
|         @out.flush |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       def schedule_expiration |       def schedule_expiration | ||||||
|         if @deploy_env.expires |         if @deploy_env.expires | ||||||
|           @out <<  "Planning expiration in #{@deploy_env.expires}" |           @out <<  "Planning expiration in #{@deploy_env.expires}" | ||||||
|  | |||||||
| @ -587,6 +587,13 @@ RSpec.describe Devops::Executor::ServerExecutor, type: :executor, stubbed_connec | |||||||
|         expect(stubbed_knife).to receive(:ssh_stream).with(anything, 'chef-client --no-color', any_args) |         expect(stubbed_knife).to receive(:ssh_stream).with(anything, 'chef-client --no-color', any_args) | ||||||
|         deploy_server |         deploy_server | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       it "uses run list from named_task if it's set" do | ||||||
|  |         project.named_tasks = [{'name' => 'foo', 'run_list' => ['role[backend]', 'role[frontend]']}] | ||||||
|  |         deploy_info['named_task'] = 'foo' | ||||||
|  |         expect(stubbed_knife).to receive(:ssh_stream).with(anything, 'chef-client --no-color -o role[backend],role[frontend]', any_args) | ||||||
|  |         deploy_server | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it "uses server's key" do |     it "uses server's key" do | ||||||
|  | |||||||
| @ -22,20 +22,33 @@ RSpec.describe Devops::Model::Project, type: :model do | |||||||
|     include_examples 'field type validation', :deploy_envs, :not_nil, :non_empty_array |     include_examples 'field type validation', :deploy_envs, :not_nil, :non_empty_array | ||||||
|     include_examples 'field type validation', :description, :maybe_nil, :maybe_empty_string |     include_examples 'field type validation', :description, :maybe_nil, :maybe_empty_string | ||||||
|     include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array, :run_list |     include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array, :run_list | ||||||
|  |     include_examples 'field type validation', :named_tasks, :maybe_nil, :maybe_empty_array | ||||||
| 
 | 
 | ||||||
|     it "isn't valid when has envs with same identifier" do |     it "isn't valid when has envs with same identifier" do | ||||||
|       project = build(:project, with_deploy_env_identifiers: %w(foo foo)) |       expect(build(:project, with_deploy_env_identifiers: %w(foo foo))).not_to be_valid | ||||||
|       expect(project).not_to be_valid |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it "is valid when all envs have uniq identifiers" do |     it "is valid when all envs have uniq identifiers" do | ||||||
|       project = build(:project, with_deploy_env_identifiers: %w(foo bar)) |       expect(build(:project, with_deploy_env_identifiers: %w(foo bar))).to be_valid | ||||||
|       expect(project).to be_valid |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it "isn't valid when at least one of envs isn't valid" do |     it "isn't valid when at least one of envs isn't valid" do | ||||||
|       project = build(:project, with_deploy_env_identifiers: ['foo', nil]) |       expect(build(:project, with_deploy_env_identifiers: ['foo', nil])).not_to be_valid | ||||||
|       expect(project).not_to be_valid |     end | ||||||
|  | 
 | ||||||
|  |     describe 'named_tasks validation' do | ||||||
|  |       it 'is valid with array of hashes like {"name" => "foo", "run_list" => ["role[bar]"]}' do | ||||||
|  |         expect(build(:project, named_tasks: [{"name" => "foo", "run_list" => ["role[bar]"]}] )).to be_valid | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it "isn't valid with array of hashes with invalid run_list elements" do | ||||||
|  |         expect(build(:project, named_tasks: [{"name" => "foo", "run_list" => ["bar"]}] )).not_to be_valid | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it "isn't valid with array of hashes without name or run_list" do | ||||||
|  |         expect(build(:project, named_tasks: [{run_list: ["role[bar]"]}] )).not_to be_valid | ||||||
|  |         expect(build(:project, named_tasks: [{"name" => "foo"}] )).not_to be_valid | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     describe 'components validation' do |     describe 'components validation' do | ||||||
| @ -58,7 +71,7 @@ RSpec.describe Devops::Model::Project, type: :model do | |||||||
| 
 | 
 | ||||||
|   describe '.fields' do |   describe '.fields' do | ||||||
|     subject { described_class.fields } |     subject { described_class.fields } | ||||||
|     it { should eq %w(deploy_envs type description) } |     it { should eq %w(deploy_envs type description named_tasks) } | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe '#initialize' do |   describe '#initialize' do | ||||||
| @ -286,8 +299,8 @@ RSpec.describe Devops::Model::Project, type: :model do | |||||||
|       expect(subject['deploy_envs']).to be_an_array_of(Hash) |       expect(subject['deploy_envs']).to be_an_array_of(Hash) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'also contains descriptions and run_list' do |     it 'also contains descriptions, run_list and named_tasks' do | ||||||
|       expect(subject).to include('description', 'run_list') |       expect(subject).to include('description', 'run_list', 'named_tasks') | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'contains archived key if project is archived' do |     it 'contains archived key if project is archived' do | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Anton Chuchkalov
						Anton Chuchkalov