opsup 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0698811d56d95cb68cd1e4bc1575bacaff650c46ed2e22e4ccb84a5d2196a769'
4
- data.tar.gz: 4e65ac9d6515e35a4c5f71ed72bacda9bb17c7b188b3dd0412a76344bc4403bc
3
+ metadata.gz: 8030ca85d3e6f53108fdda9754e8aca25918716218f0bb72d0bb3c48dcbbeb8b
4
+ data.tar.gz: 62a00a6858cb1cb044d0f4f78d7f1fc28f1915819253c28aab6306d4e0026b42
5
5
  SHA512:
6
- metadata.gz: 6453421cf1c5ef732f00e21c243eb8f324ca8e486564663166fa5a892402ec041cecf1b7f160bc3e207da5c4d64267fa6d3232d7012e8020b008f6a8eb8ec2a7
7
- data.tar.gz: 76af537846ec040151228949946efdd8e3b5c93dff6dee1eedaa127d01a5e8919a8ca45c2aaa62b4f27939a157313afc7be23b37348e41d1b42990dbec939cea
6
+ metadata.gz: 7566237b3ed9fea0b6458f2691632e4ebea7739f128c0cdade3d726a218a86dbebe34d69cc5c224ea20de781599d1c6bfc03565cc22ba6f7f39cf204db4d1abb
7
+ data.tar.gz: 11cf8034044990549f00d1153983366c0c9dd67acc98b7814480e64e71fa51bff54a9fe474165e59eb20bc47a61dc2cda4be0192ecb3abe258f51c5baa1fad5d
data/README.md CHANGED
@@ -16,6 +16,7 @@ gem install opsup
16
16
 
17
17
  Currently Opsup can run these commands:
18
18
 
19
+ - `upload_cookbooks` (to S3)
19
20
  - `update_cookbooks`
20
21
  - `setup`
21
22
  - `configure`
@@ -31,7 +32,6 @@ Opsup waits until the command completes.
31
32
 
32
33
  ### TODO
33
34
 
34
- - Add a command to build cookbooks and upload them to S3
35
35
  - Write tests
36
36
  - (maybe) Load options from environment varibles or a configuration file
37
37
  - (maybe) Add commands to create, start, stop, and delete instances
@@ -2,12 +2,15 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'sorbet-runtime'
5
+ require 'aws-sdk-opsworks'
6
+ require 'aws-sdk-s3'
5
7
 
6
8
  require_relative 'opsup/version'
7
9
  require_relative 'opsup/error'
8
10
  require_relative 'opsup/config'
9
11
  require_relative 'opsup/logger'
10
12
  require_relative 'opsup/stack_operator'
13
+ require_relative 'opsup/cookbook_uploader'
11
14
  require_relative 'opsup/app'
12
15
  require_relative 'opsup/cli'
13
16
 
@@ -1,17 +1,13 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'aws-sdk-opsworks'
5
-
6
4
  module Opsup
7
5
  class App
8
6
  extend T::Sig
9
7
 
10
8
  sig { returns(Opsup::App) }
11
9
  def self.create
12
- new(
13
- logger: Opsup::Logger.instance,
14
- )
10
+ new(logger: Opsup::Logger.instance)
15
11
  end
16
12
 
17
13
  sig { params(logger: ::Logger).void }
@@ -21,6 +17,7 @@ module Opsup
21
17
 
22
18
  AVAILABLE_COMMANDS = T.let(
23
19
  %w[
20
+ upload_cookbooks
24
21
  update_cookbooks
25
22
  setup
26
23
  configure
@@ -41,15 +38,20 @@ module Opsup
41
38
  @logger.debug("Running #{commands} with #{config.to_h}")
42
39
 
43
40
  opsworks = new_opsworks_client(config)
44
- opsworks_commands = commands.map { |c| command_to_opsworks_command(c) }
45
-
46
41
  stack_operator = Opsup::StackOperator.create(opsworks: opsworks)
47
- stack_operator.run_commands(
48
- opsworks_commands,
42
+ deployer = stack_operator.new_deployer(
49
43
  stack_name: config.stack_name,
50
44
  mode: config.running_mode,
51
45
  dryrun: config.dryrun,
52
46
  )
47
+
48
+ commands.each do |command|
49
+ if command == 'upload_cookbooks'
50
+ upload_cookbooks(config)
51
+ next
52
+ end
53
+ deployer.run_command(command_to_opsworks_command(command))
54
+ end
53
55
  ensure
54
56
  @logger.warn('Finished in DRYRUN MODE') if config.dryrun
55
57
  end
@@ -73,5 +75,32 @@ module Opsup
73
75
  private def command_to_opsworks_command(command)
74
76
  command == 'update_cookbooks' ? 'update_custom_cookbooks' : command
75
77
  end
78
+
79
+ sig { params(config: Opsup::Config).void }
80
+ def upload_cookbooks(config)
81
+ if config.cookbook_url.nil?
82
+ raise Opsup::Error, 'cookbook URL is required to run upload_cookbooks'
83
+ end
84
+ if config.s3_bucket_name.nil?
85
+ raise Opsup::Error, 'S3 Bucket name is required to run upload_cookbooks'
86
+ end
87
+
88
+ s3_object_config = CookbookUploader::S3ObjectConfig.new(
89
+ bucket_name: T.must(config.s3_bucket_name),
90
+ key: "cookbook_#{config.stack_name}.tar.gz",
91
+ )
92
+
93
+ cookbook_uploader = CookbookUploader.create(s3: new_s3_client(config), config: config)
94
+ cookbook_uploader.build_and_upload(
95
+ cookbook_url: T.must(config.cookbook_url),
96
+ s3_object_config: s3_object_config,
97
+ )
98
+ end
99
+
100
+ sig { params(config: Opsup::Config).returns(Aws::S3::Client) }
101
+ private def new_s3_client(config)
102
+ creds = Aws::Credentials.new(config.aws_access_key_id, config.aws_secret_access_key)
103
+ Aws::S3::Client.new(region: config.s3_region, credentials: creds)
104
+ end
76
105
  end
77
106
  end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'optparse'
5
+ require_relative 'cli/option_builder'
5
6
 
6
7
  module Opsup
7
8
  class CLI
@@ -12,13 +13,21 @@ module Opsup
12
13
  new(
13
14
  app: Opsup::App.create,
14
15
  option_builder: Opsup::CLI::OptionBuilder.create,
16
+ env_vars: ENV.to_h,
15
17
  )
16
18
  end
17
19
 
18
- sig { params(app: Opsup::App, option_builder: Opsup::CLI::OptionBuilder).void }
19
- def initialize(app:, option_builder:)
20
+ sig do
21
+ params(
22
+ app: Opsup::App,
23
+ option_builder: Opsup::CLI::OptionBuilder,
24
+ env_vars: T::Hash[String, T.nilable(String)],
25
+ ).void
26
+ end
27
+ def initialize(app:, option_builder:, env_vars:)
20
28
  @app = T.let(app, Opsup::App)
21
29
  @option_builder = T.let(option_builder, Opsup::CLI::OptionBuilder)
30
+ @env_vars = T.let(env_vars, T::Hash[String, T.nilable(String)])
22
31
  end
23
32
 
24
33
  sig { params(argv: T::Array[String]).returns(T::Boolean) }
@@ -26,7 +35,7 @@ module Opsup
26
35
  parser = create_parser
27
36
  @option_builder.define_options(parser)
28
37
 
29
- options = {}
38
+ options = @option_builder.options_from_env_vars(@env_vars)
30
39
  begin
31
40
  # It automatically exits with a help message if necessary.
32
41
  commands = parser.parse(argv, into: options)
@@ -64,51 +73,5 @@ module Opsup
64
73
  BANNER
65
74
  end
66
75
  end
67
-
68
- class OptionBuilder
69
- extend T::Sig
70
-
71
- sig { returns(Opsup::CLI::OptionBuilder) }
72
- def self.create
73
- new
74
- end
75
-
76
- DEFAULT_OPSWORKS_REGION = 'ap-northeast-1'
77
-
78
- sig { params(parser: OptionParser).returns(OptionParser) }
79
- def define_options(parser)
80
- parser.tap do |p|
81
- p.on('-s', '--stack STACK_NAME', 'target stack name')
82
- p.on('-m', '--mode MODE', Opsup::Config::MODES.join(' | ').to_s)
83
- p.on('--aws-cred KEY_ID,SECRET_KEY', 'AWS credentials')
84
- p.on('--opsworks-region REGION', "default: #{DEFAULT_OPSWORKS_REGION}")
85
- p.on('-d', '--dryrun')
86
- end
87
- end
88
-
89
- sig { params(options: T::Hash[Symbol, T.untyped]).returns(Opsup::Config) }
90
- def generate_config(options)
91
- %w[stack aws-cred].each do |key|
92
- raise Opsup::Error, "missing required option: --#{key}" unless options[key.to_sym]
93
- end
94
-
95
- aws_key_id, aws_secret = options[:"aws-cred"].split(',')
96
- if aws_key_id.nil? || aws_secret.nil?
97
- raise Opsup::Error, "aws-cred must be 'key_id,secret_key' format"
98
- end
99
-
100
- mode = options[:mode]&.to_sym
101
- raise Opsup::Error, "invalid mode: #{mode}" if mode && !Opsup::Config::MODES.include?(mode)
102
-
103
- Opsup::Config.new(
104
- stack_name: options[:stack],
105
- aws_access_key_id: aws_key_id,
106
- aws_secret_access_key: aws_secret,
107
- opsworks_region: options[:"opsworks-region"] || DEFAULT_OPSWORKS_REGION,
108
- running_mode: mode,
109
- dryrun: options[:dryrun] || false,
110
- )
111
- end
112
- end
113
76
  end
114
77
  end
@@ -0,0 +1,77 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Opsup
5
+ class CLI
6
+ class OptionBuilder
7
+ extend T::Sig
8
+
9
+ sig { returns(Opsup::CLI::OptionBuilder) }
10
+ def self.create
11
+ new
12
+ end
13
+
14
+ DEFAULT_AWS_REGION = 'ap-northeast-1'
15
+
16
+ sig { params(parser: OptionParser).returns(OptionParser) }
17
+ def define_options(parser)
18
+ parser.tap do |p|
19
+ p.on('-s', '--stack STACK_NAME', 'target stack name')
20
+ p.on('-m', '--mode MODE', Opsup::Config::MODES.join(' | ').to_s)
21
+ p.on('--aws-cred KEY_ID,SECRET_KEY', 'AWS credentials')
22
+ p.on('--opsworks-region REGION', "default: #{DEFAULT_AWS_REGION}")
23
+ p.on('--cookbook-url URL', 'URL of cookbook to upload')
24
+ p.on('--s3-bucket NAME', 'S3 bucket name for cookbooks')
25
+ p.on('-d', '--dryrun')
26
+ end
27
+ end
28
+
29
+ sig do
30
+ params(
31
+ env_vars: T::Hash[String, T.nilable(String)],
32
+ ).returns(T::Hash[Symbol, T.untyped])
33
+ end
34
+ def options_from_env_vars(env_vars)
35
+ [
36
+ %w[stack STACK],
37
+ %w[mode MODE],
38
+ %w[aws-cred AWS_CRED],
39
+ %w[opsworks-region OPSWORKS_REGION],
40
+ %w[cookbook-url COOKBOOK_URL],
41
+ %w[s3-bucket S3_BUCKET],
42
+ %w[dryrun DRYRUN],
43
+ ].each_with_object({}) do |(key, env_key), obj|
44
+ value = env_vars["OPSUP_#{env_key}"]
45
+ obj[key.to_sym] = value if value
46
+ end
47
+ end
48
+
49
+ sig { params(options: T::Hash[Symbol, T.untyped]).returns(Opsup::Config) }
50
+ def generate_config(options)
51
+ %w[stack aws-cred].each do |key|
52
+ raise Opsup::Error, "missing required option: --#{key}" unless options[key.to_sym]
53
+ end
54
+
55
+ aws_key_id, aws_secret = options[:"aws-cred"].split(',')
56
+ if aws_key_id.nil? || aws_secret.nil?
57
+ raise Opsup::Error, "aws-cred must be 'key_id,secret_key' format"
58
+ end
59
+
60
+ mode = options[:mode]&.to_sym
61
+ raise Opsup::Error, "invalid mode: #{mode}" if mode && !Opsup::Config::MODES.include?(mode)
62
+
63
+ Opsup::Config.new(
64
+ stack_name: options[:stack],
65
+ aws_access_key_id: aws_key_id,
66
+ aws_secret_access_key: aws_secret,
67
+ opsworks_region: options[:"opsworks-region"] || DEFAULT_AWS_REGION,
68
+ cookbook_url: options[:"cookbook-url"],
69
+ s3_bucket_name: options[:"s3-bucket"],
70
+ s3_region: options[:"s3-region"] || DEFAULT_AWS_REGION,
71
+ running_mode: mode,
72
+ dryrun: options[:dryrun] || false,
73
+ )
74
+ end
75
+ end
76
+ end
77
+ end
@@ -17,6 +17,15 @@ module Opsup
17
17
  sig { returns(String) }
18
18
  attr_reader :opsworks_region
19
19
 
20
+ sig { returns(T.nilable(String)) }
21
+ attr_reader :cookbook_url
22
+
23
+ sig { returns(T.nilable(String)) }
24
+ attr_reader :s3_bucket_name
25
+
26
+ sig { returns(T.nilable(String)) }
27
+ attr_reader :s3_region
28
+
20
29
  sig { returns(Symbol) }
21
30
  attr_reader :running_mode
22
31
 
@@ -31,6 +40,9 @@ module Opsup
31
40
  aws_access_key_id: String,
32
41
  aws_secret_access_key: String,
33
42
  opsworks_region: String,
43
+ cookbook_url: T.nilable(String),
44
+ s3_bucket_name: T.nilable(String),
45
+ s3_region: T.nilable(String),
34
46
  running_mode: T.nilable(Symbol),
35
47
  dryrun: T::Boolean,
36
48
  ).void
@@ -40,6 +52,9 @@ module Opsup
40
52
  aws_access_key_id:,
41
53
  aws_secret_access_key:,
42
54
  opsworks_region:,
55
+ cookbook_url:,
56
+ s3_bucket_name: nil,
57
+ s3_region: nil,
43
58
  running_mode: nil,
44
59
  dryrun: false
45
60
  )
@@ -47,6 +62,9 @@ module Opsup
47
62
  @aws_access_key_id = T.let(aws_access_key_id, String)
48
63
  @aws_secret_access_key = T.let(aws_secret_access_key, String)
49
64
  @opsworks_region = T.let(opsworks_region, String)
65
+ @cookbook_url = T.let(cookbook_url, T.nilable(String))
66
+ @s3_bucket_name = T.let(s3_bucket_name, T.nilable(String))
67
+ @s3_region = T.let(s3_region, T.nilable(String))
50
68
  @running_mode = T.let(running_mode || MODES.fetch(0), Symbol)
51
69
  @dryrun = T.let(dryrun, T::Boolean)
52
70
  end
@@ -58,6 +76,9 @@ module Opsup
58
76
  aws_access_key_id: aws_access_key_id,
59
77
  aws_secret_access_key: aws_secret_access_key,
60
78
  opsworks_region: opsworks_region,
79
+ cookbook_url: cookbook_url,
80
+ s3_bucket_name: s3_bucket_name,
81
+ s3_region: s3_region,
61
82
  running_mode: running_mode,
62
83
  dryrun: dryrun,
63
84
  }
@@ -0,0 +1,80 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Opsup
5
+ class CookbookUploader
6
+ extend T::Sig
7
+
8
+ class S3ObjectConfig < T::Struct
9
+ const :bucket_name, String
10
+ const :key, String
11
+ end
12
+
13
+ sig do
14
+ params(
15
+ s3: Aws::S3::Client,
16
+ config: Opsup::Config,
17
+ ).returns(Opsup::CookbookUploader)
18
+ end
19
+ def self.create(s3:, config:)
20
+ new(s3: s3, config: config, logger: Opsup::Logger.instance)
21
+ end
22
+
23
+ sig do
24
+ params(
25
+ s3: Aws::S3::Client,
26
+ config: Opsup::Config,
27
+ logger: ::Logger,
28
+ ).void
29
+ end
30
+ def initialize(s3:, config:, logger:)
31
+ @s3 = T.let(s3, Aws::S3::Client)
32
+ @config = T.let(config, Opsup::Config)
33
+ @logger = T.let(logger, ::Logger)
34
+ end
35
+
36
+ sig { params(cookbook_url: String, s3_object_config: S3ObjectConfig).void }
37
+ def build_and_upload(cookbook_url:, s3_object_config:)
38
+ Dir.mktmpdir do |work_dir|
39
+ clone(work_dir, cookbook_url)
40
+ package_path = build(work_dir)
41
+ upload(package_path, s3_object_config)
42
+ end
43
+ end
44
+
45
+ sig { params(cmd: String).void }
46
+ private def system(cmd)
47
+ if @config.dryrun
48
+ @logger.info("(dryrun) #{cmd}")
49
+ else
50
+ super(cmd)
51
+ end
52
+ end
53
+
54
+ sig { params(dir: String, url: String).void }
55
+ private def clone(dir, url)
56
+ system("git clone --depth=1 #{url} #{dir}")
57
+ end
58
+
59
+ sig { params(dir: String).returns(String) }
60
+ private def build(dir)
61
+ Dir.chdir(dir) do
62
+ system('bundle')
63
+ system('bundle exec berks package built.tar.gz')
64
+ end
65
+ "#{dir}/built.tar.gz"
66
+ end
67
+
68
+ sig { params(package_path: String, object_config: S3ObjectConfig).void }
69
+ private def upload(package_path, object_config)
70
+ unless @config.dryrun
71
+ @s3.put_object(
72
+ bucket: object_config.bucket_name,
73
+ body: File.open(package_path),
74
+ key: object_config.key,
75
+ )
76
+ end
77
+ @logger.info("cookbook #{object_config.key} uploaded")
78
+ end
79
+ end
80
+ end
@@ -1,6 +1,8 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative 'stack_operator/command_deployer'
5
+
4
6
  module Opsup
5
7
  class StackOperator
6
8
  extend T::Sig
@@ -21,13 +23,12 @@ module Opsup
21
23
 
22
24
  sig do
23
25
  params(
24
- commands: T::Array[String],
25
26
  stack_name: String,
26
27
  mode: Symbol,
27
28
  dryrun: T::Boolean,
28
- ).void
29
+ ).returns(StackOperator::CommandDeployer)
29
30
  end
30
- def run_commands(commands, stack_name:, mode:, dryrun: false)
31
+ def new_deployer(stack_name:, mode:, dryrun: false)
31
32
  # Find the target stack.
32
33
  @logger.debug('Verifying the specified stack exists...')
33
34
  stacks = @opsworks.describe_stacks.stacks
@@ -50,82 +51,19 @@ module Opsup
50
51
  "#{instances.size} #{instances.size == 1 ? 'instance is' : 'instances are'} found",
51
52
  )
52
53
 
53
- # Currently Opsup deploys only the first app by default.
54
- app = apps.first
55
- instance_ids = instances.map(&:instance_id)
56
-
57
- # Run the commands sequentially.
58
- commands.each do |command|
59
- @logger.info("Running #{command} command in #{mode} mode...")
60
- run_command(
61
- command,
62
- dryrun: dryrun,
63
- mode: mode,
64
- stack: stack,
65
- app: app,
66
- instance_ids: instance_ids,
67
- )
68
- end
69
- end
70
-
71
- sig do
72
- params(
73
- command: String,
74
- dryrun: T::Boolean,
75
- mode: Symbol,
76
- stack: Aws::OpsWorks::Types::Stack,
77
- app: Aws::OpsWorks::Types::App,
78
- instance_ids: T::Array[String],
79
- ).void
80
- end
81
- private def run_command(command, dryrun:, mode:, stack:, app:, instance_ids:)
82
- case mode
83
- when :parallel
84
- @logger.info("Creating single deployment for the #{instance_ids.size} instances...")
85
- create_deployment(command, stack, app, instance_ids) unless dryrun
86
- when :serial
87
- instance_ids.each.with_index do |id, i|
88
- @logger.info("Creating deployment for instances[#{i}] (#{id})...")
89
- create_deployment(command, stack, app, [id]) unless dryrun
90
- end
91
- when :one_then_all
92
- @logger.info("Creating deployment for the first instance (#{instance_ids[0]})...")
93
- create_deployment(command, stack, app, [T.must(instance_ids[0])]) unless dryrun
94
-
95
- rest = T.must(instance_ids[1..-1])
96
- if !rest.empty?
97
- @logger.info("Creating deployment for the other #{rest.size} instances...")
98
- create_deployment(command, stack, app, rest) unless dryrun
99
- else
100
- @logger.info('No other instances exist.')
101
- end
102
- else
103
- raise "Unknown running mode: #{mode}"
104
- end
105
- end
106
-
107
- sig do
108
- params(
109
- command: String,
110
- stack: Aws::OpsWorks::Types::Stack,
111
- app: Aws::OpsWorks::Types::App,
112
- instance_ids: T::Array[String],
113
- ).void
114
- end
115
- private def create_deployment(command, stack, app, instance_ids)
116
- res = @opsworks.create_deployment(
117
- stack_id: stack.stack_id,
118
- app_id: app.app_id,
119
- instance_ids: instance_ids,
120
- command: { name: command, args: {} },
54
+ config = StackOperator::CommandDeployer::Config.new(
55
+ stack: stack,
56
+ mode: mode,
57
+ # Currently Opsup deploys only the first app by default.
58
+ app: apps.first,
59
+ instance_ids: instances.map(&:instance_id),
60
+ dryrun: dryrun,
61
+ )
62
+ StackOperator::CommandDeployer.create(
63
+ config: config,
64
+ opsworks: @opsworks,
65
+ logger: @logger,
121
66
  )
122
-
123
- @logger.info("Waiting deployment #{res.deployment_id}...")
124
- @opsworks.wait_until(:deployment_successful, {
125
- deployment_ids: [res.deployment_id],
126
- })
127
-
128
- nil
129
67
  end
130
68
  end
131
69
  end
@@ -0,0 +1,97 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Opsup
5
+ class StackOperator
6
+ class CommandDeployer
7
+ extend T::Sig
8
+
9
+ class Config < T::Struct
10
+ const :stack, Aws::OpsWorks::Types::Stack
11
+ const :mode, Symbol
12
+ const :app, Aws::OpsWorks::Types::App
13
+ const :instance_ids, T::Array[String]
14
+ const :dryrun, T::Boolean
15
+ end
16
+
17
+ sig do
18
+ params(
19
+ config: Config,
20
+ opsworks: Aws::OpsWorks::Client,
21
+ logger: ::Logger,
22
+ ).returns(Opsup::StackOperator::CommandDeployer)
23
+ end
24
+ def self.create(config:, opsworks:, logger:)
25
+ new(config: config, opsworks: opsworks, logger: logger)
26
+ end
27
+
28
+ sig do
29
+ params(
30
+ config: Config,
31
+ opsworks: Aws::OpsWorks::Client,
32
+ logger: ::Logger,
33
+ ).void
34
+ end
35
+ def initialize(config:, opsworks:, logger:)
36
+ @config = T.let(config, Config)
37
+ @opsworks = T.let(opsworks, Aws::OpsWorks::Client)
38
+ @logger = T.let(logger, ::Logger)
39
+ end
40
+
41
+ sig { params(command: String).void }
42
+ def run_command(command)
43
+ mode = @config.mode
44
+ instance_ids = @config.instance_ids
45
+ dryrun = @config.dryrun
46
+
47
+ @logger.info("Running #{command} command in #{mode} mode...")
48
+
49
+ case mode
50
+ when :parallel
51
+ @logger.info("Creating single deployment for the #{instance_ids.size} instances...")
52
+ create_deployment(command, instance_ids) unless dryrun
53
+ when :serial
54
+ instance_ids.each.with_index do |id, i|
55
+ @logger.info("Creating deployment for instances[#{i}] (#{id})...")
56
+ create_deployment(command, [id]) unless dryrun
57
+ end
58
+ when :one_then_all
59
+ @logger.info("Creating deployment for the first instance (#{instance_ids[0]})...")
60
+ create_deployment(command, [T.must(instance_ids[0])]) unless dryrun
61
+
62
+ rest = T.must(instance_ids[1..-1])
63
+ if !rest.empty?
64
+ @logger.info("Creating deployment for the other #{rest.size} instances...")
65
+ create_deployment(command, rest) unless dryrun
66
+ else
67
+ @logger.info('No other instances exist.')
68
+ end
69
+ else
70
+ raise "Unknown running mode: #{mode}"
71
+ end
72
+ end
73
+
74
+ sig do
75
+ params(
76
+ command: String,
77
+ instance_ids: T::Array[String],
78
+ ).void
79
+ end
80
+ private def create_deployment(command, instance_ids)
81
+ res = @opsworks.create_deployment(
82
+ stack_id: @config.stack.stack_id,
83
+ app_id: @config.app.app_id,
84
+ instance_ids: instance_ids,
85
+ command: { name: command, args: {} },
86
+ )
87
+
88
+ @logger.info("Waiting deployment #{res.deployment_id}...")
89
+ @opsworks.wait_until(:deployment_successful, {
90
+ deployment_ids: [res.deployment_id],
91
+ })
92
+
93
+ nil
94
+ end
95
+ end
96
+ end
97
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Opsup
5
- VERSION = '0.0.2'
5
+ VERSION = '0.0.3'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opsup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ryym
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-25 00:00:00.000000000 Z
11
+ date: 2019-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-opsworks
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-s3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rubocop
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,10 +94,13 @@ files:
80
94
  - lib/opsup.rb
81
95
  - lib/opsup/app.rb
82
96
  - lib/opsup/cli.rb
97
+ - lib/opsup/cli/option_builder.rb
83
98
  - lib/opsup/config.rb
99
+ - lib/opsup/cookbook_uploader.rb
84
100
  - lib/opsup/error.rb
85
101
  - lib/opsup/logger.rb
86
102
  - lib/opsup/stack_operator.rb
103
+ - lib/opsup/stack_operator/command_deployer.rb
87
104
  - lib/opsup/version.rb
88
105
  homepage: https://github.com/ryym/opsup
89
106
  licenses: