hako 2.11.0 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 001e7a2b3dccc96340e80481753f1090728f9f2cca4f27e94f7fca284e6a65f1
4
- data.tar.gz: 544f03662039b57ef3e428d0de4b98a5a85dada6e41486ea8ce02777f4d305e2
3
+ metadata.gz: 1c1298dda5d9e120f1856ed3a559c520451b1023384d1a56bd921f66c70f6da5
4
+ data.tar.gz: 833a89a305a9e075df8016e90a7d4ad45f18c29ad208197e3ebdacba5a60848b
5
5
  SHA512:
6
- metadata.gz: 2c20a94341bc32ea7f1ec3e02057b09aa4e4805c1fde173e136a7ad62a10b01395c16295afdc76c925a606d884fe55528c57cdbbff71b0210a5e503c34fe216e
7
- data.tar.gz: ff1994cf309def51247e541876a6af52abb36b5ec12799cdad783de84791e0bcadb6fbc00f463c0308711db5191cce0a08804d69009207f3c5dba2cc696d6547
6
+ metadata.gz: bfba96a068f38a760e7760188574e7b5afe2dd5400ce745905f3611f71fe18f87d2cbe446878c2d00ee55e56b423ac0185baa96c91737b10847f3f77442d5035
7
+ data.tar.gz: cfa5202766106d88e125cba58011fcccff3954a843c2fdc56a301e62d476239b1ae955b627de3dfbcf185e08bfb721418669c6f86548f68d55765f164e969e56
@@ -2,14 +2,17 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
4
  DisplayCopNames: true
5
- TargetRubyVersion: 2.3
5
+ TargetRubyVersion: 2.5
6
+ NewCops: disable
6
7
 
7
- Layout/IndentFirstArgument:
8
+ Layout/FirstArgumentIndentation:
9
+ Enabled: false
10
+ Layout/LineLength:
8
11
  Enabled: false
9
12
 
10
13
  Naming/PredicateName:
11
14
  Enabled: false
12
- Naming/UncommunicativeMethodParamName:
15
+ Naming/MethodParameterName:
13
16
  Enabled: false
14
17
  Naming/MemoizedInstanceVariableName:
15
18
  Enabled: false
@@ -35,6 +38,8 @@ Style/RaiseArgs:
35
38
  EnforcedStyle: compact
36
39
  Style/SignalException:
37
40
  Enabled: false
41
+ Style/SoleNestedConditional:
42
+ Enabled: false
38
43
  Style/StderrPuts:
39
44
  Enabled: false
40
45
  Style/TrailingCommaInArguments:
@@ -6,8 +6,6 @@ Metrics/ClassLength:
6
6
  Enabled: false
7
7
  Metrics/CyclomaticComplexity:
8
8
  Enabled: false
9
- Metrics/LineLength:
10
- Enabled: false
11
9
  Metrics/MethodLength:
12
10
  Enabled: false
13
11
  Metrics/ParameterLists:
@@ -1,12 +1,10 @@
1
1
  language: ruby
2
2
  sudo: false
3
3
  rvm:
4
- - 2.3.4
5
- - 2.4.1
4
+ - 2.5.8
5
+ - 2.6.6
6
+ - 2.7.2
6
7
  - ruby-head
7
- before_install:
8
- - gem update --system # https://github.com/rubygems/rubygems/pull/1819
9
- - gem install bundler
10
8
  matrix:
11
9
  allow_failures:
12
10
  - rvm: ruby-head
@@ -1,3 +1,32 @@
1
+ # 2.15.0 (2020-11-02)
2
+ ## New features
3
+ - Support protocol_version and matcher option of ALB target groups
4
+
5
+ # 2.14.0 (2020-05-20)
6
+ ## New features
7
+ - Support tags for task definition and propagate them to ECS tasks
8
+ - Now all created ECS services and launched ECS tasks have `propagate_tags=TASK_DEFINITION` parameter.
9
+ - Support repository_credentials
10
+
11
+ # 2.13.0 (2020-01-10)
12
+ ## New features
13
+ - Support capacity provider strategy
14
+
15
+ ## Bug fixes
16
+ - Do not try to update assign_public_ip when it is not changed
17
+
18
+ # 2.12.0 (2019-09-09)
19
+ ## New features
20
+ - Support more overrides options for `hako oneshot`
21
+ - `--app-cpu`, `--app-memory` and `--app-memory-reservation` are added
22
+
23
+ ## Bug fixes
24
+ - Show `--health-*` options in dry-run
25
+
26
+ # 2.11.1 (2019-05-17)
27
+ ## Bug fixes
28
+ - Fix comparison of `system_controls` parameter
29
+
1
30
  # 2.11.0 (2019-05-17)
2
31
  ## New features
3
32
  - Support `system_controls` parameter in container definition
@@ -0,0 +1,60 @@
1
+ {
2
+ scheduler: {
3
+ type: 'ecs',
4
+ region: 'ap-northeast-1',
5
+ cluster: 'eagletmt',
6
+ desired_count: 2,
7
+ role: 'ecsServiceRole',
8
+ elb_v2: {
9
+ // Specify protocol_version for gRPC servers
10
+ protocol_version: 'GRPC',
11
+ // VPC id where the target group is located
12
+ vpc_id: 'vpc-WWWWWWWW',
13
+ // If you want internal ELB, then use 'scheme'. (ex. internal service that like microservice inside VPC)
14
+ scheme: 'internal',
15
+ // Health check path of the target group
16
+ health_check_path: '/AWS.ELB/healthcheck',
17
+ listeners: [
18
+ {
19
+ port: 50051,
20
+ protocol: 'HTTPS',
21
+ certificate_arn: 'arn:aws:acm:ap-northeast-1:012345678901:certificate/01234567-89ab-cdef-0123-456789abcdef',
22
+ },
23
+ ],
24
+ subnets: ['subnet-XXXXXXXX', 'subnet-YYYYYYYY'],
25
+ security_groups: ['sg-ZZZZZZZZ'],
26
+ load_balancer_attributes: {
27
+ 'access_logs.s3.enabled': 'true',
28
+ 'access_logs.s3.bucket': 'hako-access-logs',
29
+ 'access_logs.s3.prefix': 'hako-hello-grpc',
30
+ },
31
+ target_group_attributes: {
32
+ // http://docs.aws.amazon.com/en_us/elasticloadbalancing/latest/application/load-balancer-target-groups.html#target-group-attributes
33
+ 'deregistration_delay.timeout_seconds': '20',
34
+ },
35
+ // Route ELB traffic to app container directly
36
+ container_name: 'app',
37
+ container: 50051,
38
+ },
39
+ },
40
+ app: {
41
+ image: 'awesome-grpc-server',
42
+ memory: 128,
43
+ cpu: 256,
44
+ env: {
45
+ PORT: '50051',
46
+ },
47
+ secrets: [{
48
+ name: 'MESSAGE',
49
+ value_from: 'arn:aws:ssm:ap-northeast-1:012345678901:parameter/hako/hello-grpc/secret-message',
50
+ }],
51
+ port_mappings: [
52
+ {
53
+ container_port: 50051,
54
+ host_port: 0,
55
+ protocol: 'tcp',
56
+ },
57
+ ],
58
+ },
59
+ scripts: [],
60
+ }
@@ -19,16 +19,16 @@ Gem::Specification.new do |spec|
19
19
  spec.bindir = 'exe'
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
- spec.required_ruby_version = '>= 2.3.0'
22
+ spec.required_ruby_version = '>= 2.5.0'
23
23
 
24
24
  spec.add_dependency 'aws-sdk-applicationautoscaling'
25
25
  spec.add_dependency 'aws-sdk-autoscaling'
26
26
  spec.add_dependency 'aws-sdk-cloudwatch'
27
27
  spec.add_dependency 'aws-sdk-cloudwatchlogs'
28
28
  spec.add_dependency 'aws-sdk-ec2'
29
- spec.add_dependency 'aws-sdk-ecs', '>= 1.31.0'
29
+ spec.add_dependency 'aws-sdk-ecs', '>= 1.54.0'
30
30
  spec.add_dependency 'aws-sdk-elasticloadbalancing'
31
- spec.add_dependency 'aws-sdk-elasticloadbalancingv2'
31
+ spec.add_dependency 'aws-sdk-elasticloadbalancingv2', '>= 1.54.0'
32
32
  spec.add_dependency 'aws-sdk-s3'
33
33
  spec.add_dependency 'aws-sdk-servicediscovery'
34
34
  spec.add_dependency 'aws-sdk-sns'
@@ -147,6 +147,8 @@ module Hako
147
147
  end
148
148
 
149
149
  class Oneshot
150
+ Overrides = Struct.new(:app_cpu, :app_memory, :app_memory_reservation)
151
+
150
152
  def run(argv)
151
153
  parse!(argv)
152
154
  require 'hako/application'
@@ -162,7 +164,7 @@ module Hako
162
164
  else
163
165
  {}
164
166
  end
165
- Commander.new(Application.new(@definition_path, options)).oneshot(@argv, tag: @tag, containers: @containers, env: @env, dry_run: @dry_run, no_wait: @no_wait)
167
+ Commander.new(Application.new(@definition_path, options)).oneshot(@argv, tag: @tag, containers: @containers, env: @env, dry_run: @dry_run, no_wait: @no_wait, overrides: @overrides)
166
168
  end
167
169
 
168
170
  def parse!(argv)
@@ -171,6 +173,7 @@ module Hako
171
173
  @env = {}
172
174
  @verbose = false
173
175
  @no_wait = false
176
+ @overrides = Overrides.new
174
177
  parser.parse!(argv)
175
178
  @definition_path = argv.shift
176
179
  @argv = argv
@@ -194,6 +197,9 @@ module Hako
194
197
  k, v = arg.split('=', 2)
195
198
  @env[k] = v
196
199
  end
200
+ opts.on('--app-cpu=VAL', Integer, 'Override the default cpu for the app container') { |v| @overrides.app_cpu = v }
201
+ opts.on('--app-memory=VAL', Integer, 'Override the default memory for the app container') { |v| @overrides.app_memory = v }
202
+ opts.on('--app-memory-reservation=VAL', Integer, 'Override the default memory reservation for the app container') { |v| @overrides.app_memory_reservation = v }
197
203
  end
198
204
  end
199
205
  end
@@ -18,7 +18,7 @@ module Hako
18
18
  # @param [String, nil] tag
19
19
  # @param [Boolean] dry_run
20
20
  # @return [nil]
21
- def deploy(force: false, tag:, dry_run: false, timeout:)
21
+ def deploy(tag:, timeout:, force: false, dry_run: false)
22
22
  containers = load_containers(tag, dry_run: dry_run)
23
23
  scripts = @app.definition.fetch('scripts', []).map { |config| load_script(config, dry_run: dry_run) }
24
24
  volumes = @app.definition.fetch('volumes', {})
@@ -46,8 +46,9 @@ module Hako
46
46
  # @param [Hash<String, String>] env
47
47
  # @param [Boolean] dry_run
48
48
  # @param [Boolean] no_wait
49
+ # @param [Hako::CLI::Oneshot::Overrides, nil] overrides
49
50
  # @return [nil]
50
- def oneshot(commands, tag:, containers:, env: {}, dry_run: false, no_wait: false)
51
+ def oneshot(commands, tag:, containers:, env: {}, dry_run: false, no_wait: false, overrides: nil)
51
52
  containers = load_containers(tag, dry_run: dry_run, with: containers)
52
53
  scripts = @app.definition.fetch('scripts', []).map { |config| load_script(config, dry_run: dry_run) }
53
54
  volumes = @app.definition.fetch('volumes', {})
@@ -55,7 +56,7 @@ module Hako
55
56
 
56
57
  scripts.each { |script| script.oneshot_starting(containers) }
57
58
  exit_code = with_oneshot_signal_handlers(scheduler) do
58
- scheduler.oneshot(containers, commands, env, no_wait: no_wait)
59
+ scheduler.oneshot(containers, commands, env, no_wait: no_wait, overrides: overrides)
59
60
  end
60
61
  scripts.each { |script| script.oneshot_finished(containers) }
61
62
  exit exit_code
@@ -125,7 +126,7 @@ module Hako
125
126
  # @param [Boolean] dry_run
126
127
  # @param [Integer] timeout
127
128
  # @return [Scheduler]
128
- def load_scheduler(scheduler_definition, scripts, volumes: {}, force: false, dry_run:, timeout: nil)
129
+ def load_scheduler(scheduler_definition, scripts, dry_run:, volumes: {}, force: false, timeout: nil)
129
130
  Loader.new(Hako::Schedulers, 'hako/schedulers').load(scheduler_definition.fetch('type')).new(@app.id, scheduler_definition, volumes: volumes, scripts: scripts, force: force, dry_run: dry_run, timeout: timeout)
130
131
  end
131
132
 
@@ -213,6 +213,15 @@ module Hako
213
213
  end
214
214
  end
215
215
 
216
+ # @return [Hash, nil]
217
+ def repository_credentials
218
+ if @definition.key?('repository_credentials')
219
+ {
220
+ credentials_parameter: @definition['repository_credentials'].fetch('credentials_parameter'),
221
+ }
222
+ end
223
+ end
224
+
216
225
  private
217
226
 
218
227
  PROVIDERS_KEY = '$providers'
@@ -7,7 +7,7 @@ module Hako
7
7
  class File < EnvProvider
8
8
  # @param [Pathname] root_path
9
9
  # @param [Hash<String, Object>] options
10
- def initialize(root_path, options)
10
+ def initialize(root_path, options) # rubocop:disable Lint/MissingSuper
11
11
  unless options['path']
12
12
  validation_error!('path must be set')
13
13
  end
@@ -8,7 +8,7 @@ module Hako
8
8
  class Yaml < EnvProvider
9
9
  # @param [Pathname] root_path
10
10
  # @param [Hash<String, Object>] options
11
- def initialize(root_path, options)
11
+ def initialize(root_path, options) # rubocop:disable Lint/MissingSuper
12
12
  unless options['path']
13
13
  validation_error!('path must be set')
14
14
  end
@@ -74,6 +74,15 @@ module Hako
74
74
  @memory = options.fetch('memory', nil)
75
75
  @requires_compatibilities = options.fetch('requires_compatibilities', nil)
76
76
  @launch_type = options.fetch('launch_type', nil)
77
+ if options.key?('capacity_provider_strategy')
78
+ @capacity_provider_strategy = options.fetch('capacity_provider_strategy').map do |strategy|
79
+ {
80
+ capacity_provider: strategy.fetch('capacity_provider'),
81
+ weight: strategy.fetch('weight', nil),
82
+ base: strategy.fetch('base', nil),
83
+ }
84
+ end
85
+ end
77
86
  @platform_version = options.fetch('platform_version', nil)
78
87
  if options.key?('network_configuration')
79
88
  network_configuration = options.fetch('network_configuration')
@@ -91,6 +100,7 @@ module Hako
91
100
  if options['service_discovery']
92
101
  @service_discovery = EcsServiceDiscovery.new(options.fetch('service_discovery'), @region, dry_run: @dry_run)
93
102
  end
103
+ @tags = options.fetch('tags', {}).map { |k, v| { key: k, value: v.to_s } }
94
104
 
95
105
  @started_at = nil
96
106
  @container_instance_arn = nil
@@ -198,8 +208,9 @@ module Hako
198
208
  # @param [Array<String>] commands
199
209
  # @param [Hash<String, String>] env
200
210
  # @param [Boolean] no_wait
211
+ # @param [Hako::CLI::Oneshot::Overrides, nil] overrides
201
212
  # @return [Integer] Returns exit code
202
- def oneshot(containers, commands, env, no_wait: false)
213
+ def oneshot(containers, commands, env, no_wait: false, overrides: nil)
203
214
  definitions = create_definitions(containers)
204
215
 
205
216
  if @dry_run
@@ -210,7 +221,7 @@ module Hako
210
221
  if d[:name] == 'app'
211
222
  d[:command] = commands
212
223
  end
213
- print_definition_in_cli_format(d, additional_env: env)
224
+ print_definition_in_cli_format(d, additional_env: env, overrides: overrides)
214
225
  check_secrets(d)
215
226
  end
216
227
  0
@@ -221,7 +232,7 @@ module Hako
221
232
  else
222
233
  Hako.logger.info "Task definition isn't changed: #{task_definition.task_definition_arn}"
223
234
  end
224
- @task = run_task(task_definition, commands, env)
235
+ @task = run_task(task_definition, commands, env, overrides)
225
236
  Hako.logger.info "Started task: #{@task.task_arn}"
226
237
  @scripts.each { |script| script.oneshot_started(self) }
227
238
  if no_wait
@@ -454,8 +465,9 @@ module Hako
454
465
 
455
466
  # @param [Array<Hash>] desired_definitions
456
467
  # @param [Aws::ECS::Types::TaskDefinition] actual_definition
457
- # @return [Array<Boolean]
458
- def task_definition_changed?(desired_definitions, actual_definition)
468
+ # @param [Array<Aws::ECS::Types::Tag>] actual_tags
469
+ # @return [Array<Boolean>]
470
+ def task_definition_changed?(desired_definitions, actual_definition, actual_tags)
459
471
  if @force
460
472
  return true
461
473
  end
@@ -504,6 +516,12 @@ module Hako
504
516
  return true
505
517
  end
506
518
 
519
+ actual_tags_set = Set.new(actual_tags.map { |t| { key: t.key, value: t.value } })
520
+ tags_set = Set.new(@tags)
521
+ if actual_tags_set != tags_set
522
+ return true
523
+ end
524
+
507
525
  false
508
526
  end
509
527
 
@@ -525,7 +543,10 @@ module Hako
525
543
  # @return [Array<Boolean, Aws::ECS::Types::TaskDefinition>]
526
544
  def register_task_definition(definitions)
527
545
  current_task_definition = describe_task_definition(@app_id)
528
- if task_definition_changed?(definitions, current_task_definition)
546
+ if current_task_definition
547
+ current_tags = ecs_client.list_tags_for_resource(resource_arn: current_task_definition.task_definition_arn).tags
548
+ end
549
+ if task_definition_changed?(definitions, current_task_definition, current_tags)
529
550
  new_task_definition = ecs_client.register_task_definition(
530
551
  family: @app_id,
531
552
  task_role_arn: @task_role_arn,
@@ -536,6 +557,7 @@ module Hako
536
557
  requires_compatibilities: @requires_compatibilities,
537
558
  cpu: @cpu,
538
559
  memory: @memory,
560
+ tags: @tags.empty? ? nil : @tags,
539
561
  ).task_definition
540
562
  [true, new_task_definition]
541
563
  else
@@ -555,34 +577,36 @@ module Hako
555
577
  # @return [Array<Boolean, Aws::ECS::Types::TaskDefinition]
556
578
  def register_task_definition_for_oneshot(definitions)
557
579
  10.times do |i|
558
- begin
559
- family = "#{@app_id}-oneshot"
560
- current_task_definition = describe_task_definition(family)
561
- if task_definition_changed?(definitions, current_task_definition)
562
- new_task_definition = ecs_client.register_task_definition(
563
- family: family,
564
- task_role_arn: @task_role_arn,
565
- execution_role_arn: @execution_role_arn,
566
- network_mode: @network_mode,
567
- container_definitions: definitions,
568
- volumes: volumes_definition,
569
- requires_compatibilities: @requires_compatibilities,
570
- cpu: @cpu,
571
- memory: @memory,
572
- ).task_definition
573
- return [true, new_task_definition]
574
- else
575
- return [false, current_task_definition]
576
- end
577
- rescue Aws::ECS::Errors::ClientException => e
578
- if e.message.include?('Too many concurrent attempts to create a new revision of the specified family')
579
- Hako.logger.error(e.message)
580
- interval = 2**i + rand(0.0..10.0)
581
- Hako.logger.error("Retrying register_task_definition_for_oneshot after #{interval} seconds")
582
- sleep(interval)
583
- else
584
- raise e
585
- end
580
+ family = "#{@app_id}-oneshot"
581
+ current_task_definition = describe_task_definition(family)
582
+ if current_task_definition
583
+ current_tags = ecs_client.list_tags_for_resource(resource_arn: current_task_definition.task_definition_arn).tags
584
+ end
585
+ if task_definition_changed?(definitions, current_task_definition, current_tags)
586
+ new_task_definition = ecs_client.register_task_definition(
587
+ family: family,
588
+ task_role_arn: @task_role_arn,
589
+ execution_role_arn: @execution_role_arn,
590
+ network_mode: @network_mode,
591
+ container_definitions: definitions,
592
+ volumes: volumes_definition,
593
+ requires_compatibilities: @requires_compatibilities,
594
+ cpu: @cpu,
595
+ memory: @memory,
596
+ tags: @tags.empty? ? nil : @tags,
597
+ ).task_definition
598
+ return [true, new_task_definition]
599
+ else
600
+ return [false, current_task_definition]
601
+ end
602
+ rescue Aws::ECS::Errors::ClientException => e
603
+ if e.message.include?('Too many concurrent attempts to create a new revision of the specified family')
604
+ Hako.logger.error(e.message)
605
+ interval = 2**i + rand(0.0..10.0)
606
+ Hako.logger.error("Retrying register_task_definition_for_oneshot after #{interval} seconds")
607
+ sleep(interval)
608
+ else
609
+ raise e
586
610
  end
587
611
  end
588
612
  raise Error.new('Unable to register task definition for oneshot due to too many client errors')
@@ -652,33 +676,28 @@ module Hako
652
676
  readonly_root_filesystem: container.readonly_root_filesystem,
653
677
  docker_security_options: container.docker_security_options,
654
678
  system_controls: container.system_controls,
679
+ repository_credentials: container.repository_credentials,
655
680
  }
656
681
  end
657
682
 
658
683
  # @param [Aws::ECS::Types::TaskDefinition] task_definition
659
684
  # @param [Array<String>] commands
660
685
  # @param [Hash<String, String>] env
686
+ # @param [Hako::CLI::Oneshot::Overrides] overrides
661
687
  # @return [Aws::ECS::Types::Task]
662
- def run_task(task_definition, commands, env)
663
- environment = env.map { |k, v| { name: k, value: v } }
688
+ def run_task(task_definition, commands, env, overrides)
664
689
  result = ecs_client.run_task(
665
690
  cluster: @cluster,
666
691
  task_definition: task_definition.task_definition_arn,
667
- overrides: {
668
- container_overrides: [
669
- {
670
- name: 'app',
671
- command: commands,
672
- environment: environment,
673
- },
674
- ],
675
- },
692
+ overrides: overrides_option(commands, env, overrides),
676
693
  count: 1,
677
694
  placement_constraints: @placement_constraints,
678
695
  started_by: 'hako oneshot',
679
696
  launch_type: @launch_type,
697
+ capacity_provider_strategy: @capacity_provider_strategy,
680
698
  platform_version: @platform_version,
681
699
  network_configuration: @network_configuration,
700
+ propagate_tags: 'TASK_DEFINITION',
682
701
  )
683
702
  result.failures.each do |failure|
684
703
  Hako.logger.error("#{failure.arn} #{failure.reason}")
@@ -702,6 +721,25 @@ module Hako
702
721
  end
703
722
  end
704
723
 
724
+ # @param [Array<String>] commands
725
+ # @param [Hash<String, String>] env
726
+ # @param [Hako::CLI::Oneshot::Overrides, nil] overrides
727
+ # @doc https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerOverride.html
728
+ def overrides_option(commands, env, overrides)
729
+ {
730
+ container_overrides: [
731
+ {
732
+ name: 'app',
733
+ cpu: overrides&.app_cpu,
734
+ memory: overrides&.app_memory,
735
+ memory_reservation: overrides&.app_memory_reservation,
736
+ command: commands,
737
+ environment: env.map { |k, v| { name: k, value: v } },
738
+ },
739
+ ],
740
+ }
741
+ end
742
+
705
743
  # @return [Fixnum]
706
744
  def wait_for_oneshot_finish
707
745
  containers = wait_for_task(@task)
@@ -852,6 +890,7 @@ module Hako
852
890
  desired_count: @desired_count,
853
891
  task_definition: task_definition_arn,
854
892
  deployment_configuration: @deployment_configuration,
893
+ capacity_provider_strategy: @capacity_provider_strategy,
855
894
  platform_version: @platform_version,
856
895
  network_configuration: @network_configuration,
857
896
  health_check_grace_period_seconds: @health_check_grace_period_seconds,
@@ -860,6 +899,20 @@ module Hako
860
899
  # Keep current desired_count if autoscaling is enabled
861
900
  params[:desired_count] = current_service.desired_count
862
901
  end
902
+ # Copy the current capacity provider strategy in order to avoid a
903
+ # perpetual diff when the service is created with no strategy to use the
904
+ # cluster's default capacity provider strategy, which results in the
905
+ # strategy being set to the default strategy at that moment.
906
+ # It is not allowed to update the service to use the cluster's default
907
+ # capacity provider strategy when it is using a non-default capacity
908
+ # provider strategy.
909
+ params[:capacity_provider_strategy] ||= current_service.capacity_provider_strategy&.map(&:to_h)
910
+ if different_capacity_provider_strategy?(params[:capacity_provider_strategy], current_service.capacity_provider_strategy)
911
+ # Switching from launch type to capacity provider strategy or making
912
+ # a change to a capacity provider strategy requires to force a new
913
+ # deployment.
914
+ params[:force_new_deployment] = true
915
+ end
863
916
  warn_placement_policy_change(current_service)
864
917
  warn_service_registries_change(current_service)
865
918
  if service_changed?(current_service, params)
@@ -883,9 +936,11 @@ module Hako
883
936
  placement_strategy: @placement_strategy,
884
937
  scheduling_strategy: @scheduling_strategy,
885
938
  launch_type: @launch_type,
939
+ capacity_provider_strategy: @capacity_provider_strategy,
886
940
  platform_version: @platform_version,
887
941
  network_configuration: @network_configuration,
888
942
  health_check_grace_period_seconds: @health_check_grace_period_seconds,
943
+ propagate_tags: 'TASK_DEFINITION',
889
944
  }
890
945
  if @scheduling_strategy != 'DAEMON'
891
946
  params[:desired_count] = 0
@@ -1154,17 +1209,33 @@ module Hako
1154
1209
 
1155
1210
  # @param [Hash] definition
1156
1211
  # @param [Hash<String, String>] additional_env
1212
+ # @param [Hako::CLI::Oneshot::Overrides, nil] overrides
1157
1213
  # @return [nil]
1158
- def print_definition_in_cli_format(definition, additional_env: {})
1214
+ def print_definition_in_cli_format(definition, additional_env: {}, overrides: nil)
1159
1215
  cmd = %w[docker run]
1160
1216
  cmd << '--name' << definition.fetch(:name)
1161
- cmd << '--cpu-shares' << definition.fetch(:cpu)
1162
- if definition[:memory]
1163
- cmd << '--memory' << "#{definition[:memory]}M"
1164
- end
1165
- if definition[:memory_reservation]
1166
- cmd << '--memory-reservation' << "#{definition[:memory_reservation]}M"
1217
+
1218
+ if overrides && definition.fetch(:name) == 'app'
1219
+ cpu = overrides.app_cpu || definition.fetch(:cpu)
1220
+ cmd << '--cpu-shares' << cpu
1221
+ memory = overrides.app_memory || definition[:memory]
1222
+ if memory
1223
+ cmd << '--memory' << "#{memory}M"
1224
+ end
1225
+ memory_reservation = overrides.app_memory_reservation || definition[:memory_reservation]
1226
+ if memory_reservation
1227
+ cmd << '--memory-reservation' << "#{memory_reservation}M"
1228
+ end
1229
+ else
1230
+ cmd << '--cpu-shares' << definition.fetch(:cpu)
1231
+ if definition[:memory]
1232
+ cmd << '--memory' << "#{definition[:memory]}M"
1233
+ end
1234
+ if definition[:memory_reservation]
1235
+ cmd << '--memory-reservation' << "#{definition[:memory_reservation]}M"
1236
+ end
1167
1237
  end
1238
+
1168
1239
  definition.fetch(:links).each do |link|
1169
1240
  cmd << '--link' << link
1170
1241
  end
@@ -1227,9 +1298,6 @@ module Hako
1227
1298
  cmd << '--tmpfs' << "#{tmpfs[:container_path]}:#{options.join(',')}"
1228
1299
  end
1229
1300
  end
1230
- definition.fetch(:volumes_from).each do |volumes_from|
1231
- p volumes_from
1232
- end
1233
1301
  if definition[:user]
1234
1302
  cmd << '--user' << definition[:user]
1235
1303
  end
@@ -1247,6 +1315,28 @@ module Hako
1247
1315
  cmd << '--sysctl' << "#{system_control.fetch(:namespace)}=#{system_control.fetch(:value)}"
1248
1316
  end
1249
1317
  end
1318
+ if definition[:health_check]
1319
+ if definition[:health_check][:command]
1320
+ health_check_command_type = definition[:health_check][:command][0]
1321
+ case health_check_command_type
1322
+ when 'NONE'
1323
+ cmd << '--no-healthcheck'
1324
+ when 'CMD', 'CMD-SHELL'
1325
+ health_check_command = definition[:health_check][:command][1..-1].join(' ')
1326
+ cmd << '--health-cmd' << health_check_command.inspect
1327
+ else
1328
+ raise "Health check command type #{health_check_command_type} is not supported. CMD, CMD-SHELL and NONE are supported."
1329
+ end
1330
+ end
1331
+ if definition[:health_check][:retries]
1332
+ cmd << '--health-retries' << definition[:health_check][:retries]
1333
+ end
1334
+ %i[interval timeout start_period].each do |property|
1335
+ if definition[:health_check][property]
1336
+ cmd << "--health-#{property}" << "#{definition[:health_check][property]}s"
1337
+ end
1338
+ end
1339
+ end
1250
1340
 
1251
1341
  cmd << "\\\n "
1252
1342
  definition.fetch(:environment).each do |env|
@@ -1301,6 +1391,15 @@ module Hako
1301
1391
  nil
1302
1392
  end
1303
1393
 
1394
+ # @param [Hash, nil] expected_strategy
1395
+ # @param [Aws::ECS::Types::CapacityProviderStrategyItem, nil] actual_strategy
1396
+ # @return [Boolean]
1397
+ def different_capacity_provider_strategy?(expected_strategy, actual_strategy)
1398
+ expected = (expected_strategy || []).map { |s| [s[:capacity_provider], s[:weight] || 0, s[:base] || 0] }.sort
1399
+ actual = (actual_strategy || []).map { |s| [s.capacity_provider, s.weight, s.base] }.sort
1400
+ expected != actual
1401
+ end
1402
+
1304
1403
  # @param [Aws::ECS::Types::Service] service
1305
1404
  # @return [nil]
1306
1405
  def warn_placement_policy_change(service)
@@ -162,9 +162,7 @@ module Hako
162
162
  end
163
163
 
164
164
  class Policy
165
- attr_reader :policy_type
166
- attr_reader :alarms, :cooldown, :adjustment_type, :scaling_adjustment, :metric_interval_lower_bound, :metric_interval_upper_bound, :metric_aggregation_type
167
- attr_reader :target_value, :predefined_metric_type, :scale_out_cooldown, :scale_in_cooldown, :disable_scale_in
165
+ attr_reader :policy_type, :alarms, :cooldown, :adjustment_type, :scaling_adjustment, :metric_interval_lower_bound, :metric_interval_upper_bound, :metric_aggregation_type, :target_value, :predefined_metric_type, :scale_out_cooldown, :scale_in_cooldown, :disable_scale_in
168
166
 
169
167
  # @param [Hash] options
170
168
  def initialize(options)
@@ -46,6 +46,7 @@ module Hako
46
46
  struct.member(:readonly_root_filesystem, Schema::Nullable.new(Schema::Boolean.new))
47
47
  struct.member(:docker_security_options, Schema::Nullable.new(Schema::UnorderedArray.new(Schema::String.new)))
48
48
  struct.member(:system_controls, Schema::Nullable.new(system_controls_schema))
49
+ struct.member(:repository_credentials, Schema::Nullable.new(repository_credentials_schema))
49
50
  end
50
51
  end
51
52
 
@@ -173,11 +174,21 @@ module Hako
173
174
  end
174
175
 
175
176
  def system_controls_schema
177
+ Schema::UnorderedArray.new(system_control_schema)
178
+ end
179
+
180
+ def system_control_schema
176
181
  Schema::Structure.new.tap do |struct|
177
182
  struct.member(:namespace, Schema::String.new)
178
183
  struct.member(:value, Schema::String.new)
179
184
  end
180
185
  end
186
+
187
+ def repository_credentials_schema
188
+ Schema::Structure.new.tap do |struct|
189
+ struct.member(:credentials_parameter, Schema::String.new)
190
+ end
191
+ end
181
192
  end
182
193
  end
183
194
  end
@@ -89,13 +89,22 @@ module Hako
89
89
  target_type: @elb_v2_config.fetch('target_type', nil),
90
90
  ).target_groups[0]
91
91
  else
92
+ matcher =
93
+ if @elb_v2_config.key?('matcher')
94
+ {
95
+ http_code: @elb_v2_config.fetch('matcher')['http_code'],
96
+ grpc_code: @elb_v2_config.fetch('matcher')['grpc_code'],
97
+ }
98
+ end
92
99
  elb_client.create_target_group(
93
100
  name: target_group_name,
94
101
  port: 80,
95
102
  protocol: 'HTTP',
103
+ protocol_version: @elb_v2_config.fetch('protocol_version', 'HTTP1'),
96
104
  vpc_id: @elb_v2_config.fetch('vpc_id'),
97
105
  health_check_path: @elb_v2_config.fetch('health_check_path', nil),
98
106
  target_type: @elb_v2_config.fetch('target_type', nil),
107
+ matcher: matcher,
99
108
  ).target_groups[0]
100
109
  end
101
110
 
@@ -23,6 +23,7 @@ module Hako
23
23
  struct.member(:desired_count, Schema::Integer.new)
24
24
  struct.member(:task_definition, Schema::String.new)
25
25
  struct.member(:deployment_configuration, Schema::WithDefault.new(deployment_configuration_schema, default_configuration))
26
+ struct.member(:capacity_provider_strategy, Schema::Nullable.new(Schema::UnorderedArray.new(capacity_provider_strategy_schema)))
26
27
  struct.member(:platform_version, Schema::WithDefault.new(Schema::String.new, 'LATEST'))
27
28
  struct.member(:network_configuration, Schema::Nullable.new(network_configuration_schema))
28
29
  struct.member(:health_check_grace_period_seconds, Schema::Nullable.new(Schema::Integer.new))
@@ -36,6 +37,14 @@ module Hako
36
37
  end
37
38
  end
38
39
 
40
+ def capacity_provider_strategy_schema
41
+ Schema::Structure.new.tap do |struct|
42
+ struct.member(:capacity_provider, Schema::String.new)
43
+ struct.member(:weight, Schema::WithDefault.new(Schema::Integer.new, 0))
44
+ struct.member(:base, Schema::WithDefault.new(Schema::Integer.new, 0))
45
+ end
46
+ end
47
+
39
48
  def network_configuration_schema
40
49
  Schema::Structure.new.tap do |struct|
41
50
  struct.member(:awsvpc_configuration, awsvpc_configuration_schema)
@@ -46,7 +55,7 @@ module Hako
46
55
  Schema::Structure.new.tap do |struct|
47
56
  struct.member(:subnets, Schema::UnorderedArray.new(Schema::String.new))
48
57
  struct.member(:security_groups, Schema::UnorderedArray.new(Schema::String.new))
49
- struct.member(:assign_public_ip, Schema::String.new)
58
+ struct.member(:assign_public_ip, Schema::WithDefault.new(Schema::String.new, 'DISABLED'))
50
59
  end
51
60
  end
52
61
 
@@ -10,7 +10,7 @@ module Hako
10
10
  class NginxFront < Script
11
11
  S3Config = Struct.new(:region, :bucket, :prefix) do
12
12
  # @param [Hash] options
13
- def initialize(options)
13
+ def initialize(options) # rubocop:disable Lint/MissingSuper
14
14
  self.region = options.fetch('region')
15
15
  self.bucket = options.fetch('bucket')
16
16
  self.prefix = options.fetch('prefix', nil)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hako
4
- VERSION = '2.11.0'
4
+ VERSION = '2.15.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hako
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.0
4
+ version: 2.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kohei Suzuki
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-17 00:00:00.000000000 Z
11
+ date: 2020-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-applicationautoscaling
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: 1.31.0
89
+ version: 1.54.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: 1.31.0
96
+ version: 1.54.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: aws-sdk-elasticloadbalancing
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: 1.54.0
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: 1.54.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: aws-sdk-s3
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -321,6 +321,7 @@ files:
321
321
  - examples/hello-cap-add-app.jsonnet
322
322
  - examples/hello-fargate-batch.jsonnet
323
323
  - examples/hello-fargate.jsonnet
324
+ - examples/hello-grpc.jsonnet
324
325
  - examples/hello-internal-nlb.jsonnet
325
326
  - examples/hello-lb-v2.jsonnet
326
327
  - examples/hello-lb.jsonnet
@@ -382,7 +383,7 @@ homepage: https://github.com/eagletmt/hako
382
383
  licenses:
383
384
  - MIT
384
385
  metadata: {}
385
- post_install_message:
386
+ post_install_message:
386
387
  rdoc_options: []
387
388
  require_paths:
388
389
  - lib
@@ -390,15 +391,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
390
391
  requirements:
391
392
  - - ">="
392
393
  - !ruby/object:Gem::Version
393
- version: 2.3.0
394
+ version: 2.5.0
394
395
  required_rubygems_version: !ruby/object:Gem::Requirement
395
396
  requirements:
396
397
  - - ">="
397
398
  - !ruby/object:Gem::Version
398
399
  version: '0'
399
400
  requirements: []
400
- rubygems_version: 3.0.3
401
- signing_key:
401
+ rubygems_version: 3.1.4
402
+ signing_key:
402
403
  specification_version: 4
403
404
  summary: Deploy Docker container
404
405
  test_files: []