hako 2.11.0 → 2.15.0

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: 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: []