kcu 0.2.0 → 0.3.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
  SHA1:
3
- metadata.gz: 2ce1f8358a691f2bb4fe73a2d74fe7e9af6775ba
4
- data.tar.gz: 1e02aa503e1da760686a663153e8de70a9c7b612
3
+ metadata.gz: b390824d729ff0b0d28f3b453aef75ee5d5e7da7
4
+ data.tar.gz: 2ca5b1df6afd4ec36facb653592df40194731ab4
5
5
  SHA512:
6
- metadata.gz: b99940b59e086dd9c45a0e1348d24dc830db891113200d813af6246e1dcb4b3d7425885952163d8896d33f0562be239709623cb66837c7d70558637ba1d9c364
7
- data.tar.gz: e4a4085bef52aef30252a84aea42a57cad5dd8c6426b28e1825b964ba0c400668a480bf6a96040a28020432fe219fa85ff2bd85fa43133a6db85f4e9a63a0b67
6
+ metadata.gz: c2ac93598773b7c07008adadb66f96b628229010ca34aa03da0f9de22c19fc3ef1cab36922f54f1ac4b4e48f1c9a062fdd493157bb220b4536cfd9c7cd5d57fd
7
+ data.tar.gz: 568488c1fe0d3aeebec2e848e0ec5b214e94336339ca9379bec27af891ad12df97b8ed8be788d7516041f95d9d543c59933f0453512f2dadeef4d3be62d8b423
data/CHANGELOG.md CHANGED
@@ -4,7 +4,12 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [0.2.0] -2017-11-26
7
+ ## [0.3.0] - 2017-11-26
8
+ ### Added
9
+ - Add easy deployment
10
+ - Restart a deployment
11
+
12
+ ## [0.2.0] - 2017-11-26
8
13
  ### Added
9
14
  - Get a single secret's decoded value
10
15
  - Set a single secret's value, given a non-encoded value (yes, we properly encode for you!)
data/README.md CHANGED
@@ -14,13 +14,64 @@ gem install kcu
14
14
 
15
15
  ## Usage
16
16
 
17
- All actions are documented in the executable:
17
+ All actions are documented in the executable. Use `--help`:
18
18
 
19
19
  ```
20
20
  kcu --help
21
21
  kcu secret list --help
22
22
  ```
23
23
 
24
+ Some examples:
25
+
26
+ ```
27
+ kcu secret list production/worker
28
+ kcu secret get production/worker sidekiq_concurrency
29
+ kcu secret set production/worker sidekiq_concurrency 10
30
+ kcu controller restart production/website
31
+ ```
32
+
33
+ ### Easy Deployment
34
+
35
+ Some teams prefer not to deploy via CD -- perhaps more planning needs to go through the deployment phase. For this type of workflow, KCU provides a simple way to deploy:
36
+
37
+ ```
38
+ kcu deploy master
39
+ ```
40
+
41
+ This must be executed in the project which contains the configuration file `kcu.yml`:
42
+
43
+ ```
44
+ ---
45
+ deploys:
46
+ - branch: master
47
+ namespace: production
48
+ template: "gcr.io/bloom-solutions/website:prod-$GIT_COMMIT"
49
+ targets:
50
+ - deployment_name: web
51
+ container: website
52
+ - deployment_name: worker
53
+ container: sidekiq
54
+ - branch: /staging_(\d+)/
55
+ namespace: staging
56
+ template: "gcr.io/bloom-solutions/website:staging-$GIT_COMMIT"
57
+ targets:
58
+ - deployment_name: web
59
+ container: website
60
+ - deployment_name: worker
61
+ container: sidekiq
62
+ ```
63
+
64
+ The command above is the short version of `kcu deploy master production`. If you will deploy the master branch to production/web/website and production/worker/sidekiq then you need not specify the target details, since this is already defined in the config file.
65
+
66
+ When deploying the a specific branch to a different namespace (like deploying the production image to the staging namespace), you may specify the namespace. For example, these commands deploy the `master` branch to the staging/web/website and staging/worker/sidekiq containers:
67
+
68
+ ```
69
+ kcu deploy master staging
70
+ ```
71
+
72
+ - Variables:
73
+ - `GIT_COMMIT`: the full, latest git commit hash of the *local* git copy in the branch
74
+
24
75
  ## Development
25
76
 
26
77
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/kcu CHANGED
@@ -8,4 +8,4 @@ $: << LIB_DIR
8
8
 
9
9
  require 'kcu'
10
10
 
11
- Kcu::Client.new.run if $0 == __FILE__
11
+ Kcu::Client.new.run(working_dir: FileUtils.pwd)
data/kcu.gemspec CHANGED
@@ -26,15 +26,20 @@ Gem::Specification.new do |spec|
26
26
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
27
  f.match(%r{^(test|spec|features)/})
28
28
  end
29
- spec.bindir = "exe"
30
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.bindir = "bin"
30
+ spec.executables = ["kcu"]
31
31
  spec.require_paths = ["lib"]
32
32
 
33
+ spec.add_dependency "activesupport", ">= 3.0"
33
34
  spec.add_dependency "awesome_print", "~> 1.8"
34
35
  spec.add_dependency "commander", "~> 4.4"
36
+ spec.add_dependency "dry-initializer", "~> 2.3"
35
37
  spec.add_dependency "light-service", "0.8.3"
38
+ spec.add_dependency "git", "~> 1.3"
39
+ spec.add_dependency "to_regexp", "0.2.1"
36
40
 
37
41
  spec.add_development_dependency "bundler", "~> 1.15"
38
42
  spec.add_development_dependency "rake", "~> 10.0"
39
43
  spec.add_development_dependency "rspec", "~> 3.0"
44
+ spec.add_development_dependency "timecop"
40
45
  end
@@ -0,0 +1,23 @@
1
+ module Kcu
2
+ class DeployAction
3
+
4
+ extend LightService::Organizer
5
+
6
+ def self.call(repo_dir, git_branch, target_namespace=nil)
7
+ with(
8
+ repo_dir: repo_dir,
9
+ git_branch: git_branch,
10
+ target_namespace: target_namespace,
11
+ ).reduce(
12
+ Deploys::GetConfig,
13
+ Deploys::GetImageConfig,
14
+ Deploys::GenImageName,
15
+ Deploys::SetTargetNamespace,
16
+ Deploys::GetTargetContainersConfig,
17
+ Deploys::GetTargetContainers,
18
+ Deploys::SetImage,
19
+ )
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Kcu
2
+ class RestartDeploymentAction
3
+
4
+ extend LightService::Organizer
5
+
6
+ def self.call(resource)
7
+ ctx = with(resource: resource).reduce(
8
+ GetResourceNamespaceAndName,
9
+ Deployments::RestartDeployment,
10
+ )
11
+ end
12
+
13
+ end
14
+ end
data/lib/kcu/client.rb CHANGED
@@ -5,7 +5,7 @@ module Kcu
5
5
 
6
6
  include Commander::Methods
7
7
 
8
- def run
8
+ def run(working_dir:)
9
9
  program :name, "Kubectl Utils (KCU)"
10
10
  program :version, Kcu::VERSION
11
11
  program :description, Kcu::SUMMARY
@@ -34,6 +34,22 @@ module Kcu
34
34
  end
35
35
  end
36
36
 
37
+ command :"deployment restart" do |c|
38
+ c.syntax = "deployment restart namespace/deployment_name"
39
+ c.description = "Restarts a deployment"
40
+ c.action do |args, options|
41
+ RestartDeploymentAction.(*args)
42
+ end
43
+ end
44
+
45
+ command :deploy do |c|
46
+ c.syntax = "deploy master"
47
+ c.description = "Deploy a branch"
48
+ c.action do |args, options|
49
+ DeployAction.(*args.insert(0, working_dir))
50
+ end
51
+ end
52
+
37
53
  run!
38
54
  end
39
55
 
@@ -0,0 +1,11 @@
1
+ module Kcu
2
+ class Container
3
+
4
+ extend Dry::Initializer
5
+
6
+ option :namespace
7
+ option :deployment_name
8
+ option :name
9
+
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ module Kcu
2
+ module Deployments
3
+ class RestartDeployment
4
+
5
+ extend LightService::Action
6
+ expects :resource_namespace, :resource_name
7
+
8
+ executed do |c|
9
+ json = { spec: { template: { metadata: { annotations: {
10
+ kcu_restarted_at: Time.now.to_i.to_s,
11
+ } } } } }.to_json
12
+
13
+ stdout_str, stderr_str, status = ExecShell.(
14
+ "kubectl",
15
+ "patch",
16
+ "deployment",
17
+ c.resource_name,
18
+ "--namespace" => c.resource_namespace,
19
+ "--patch" => "'#{json}'",
20
+ )
21
+
22
+ puts stdout_str
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ module Kcu
2
+ module Deploys
3
+ class GenImageName
4
+
5
+ extend LightService::Action
6
+ expects :image_config, :git_branch, :repo_dir
7
+ promises :image_name
8
+
9
+ executed do |c|
10
+ git = Git.open(c.repo_dir)
11
+ git.branch(c.git_branch)
12
+ git_commit = git.log(1).first.sha
13
+
14
+ c.image_name = c.image_config["template"].
15
+ gsub("$GIT_COMMIT", git_commit)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module Kcu
2
+ module Deploys
3
+ class GetConfig
4
+
5
+ CONFIG_FILE_NAME = "kcu.yml"
6
+ extend LightService::Action
7
+ expects :repo_dir
8
+ promises :config
9
+
10
+ executed do |c|
11
+ file_path = File.join(c.repo_dir, CONFIG_FILE_NAME)
12
+ if File.exists?(file_path)
13
+ c.config = YAML.load_file(file_path)
14
+ else
15
+ fail ArgumentError, "#{CONFIG_FILE_NAME} is not present in #{c.repo_dir}"
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ module Kcu
2
+ module Deploys
3
+ class GetImageConfig
4
+
5
+ extend LightService::Action
6
+ expects :git_branch, :config
7
+ promises :image_config
8
+
9
+ executed do |c|
10
+ c.image_config = catch(:config) do
11
+ c.config["deploys"].find do |conf|
12
+ config_branch = conf["branch"]
13
+ if config_branch.include?("/")
14
+ throw(:config, conf) if c.git_branch =~ config_branch.to_regexp
15
+ else
16
+ throw(:config, conf) if c.git_branch == config_branch
17
+ end
18
+ end
19
+
20
+ fail ArgumentError, "`#{c.git_branch}` branch is not configured"
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module Kcu
2
+ module Deploys
3
+ class GetTargetContainers
4
+
5
+ extend LightService::Action
6
+ expects :target_containers_config, :target_namespace
7
+ promises :target_containers
8
+
9
+ executed do |c|
10
+ config = c.target_containers_config
11
+ targets = config["targets"]
12
+ c.target_containers = targets.map do |target_config|
13
+ Container.new(
14
+ namespace: c.target_namespace,
15
+ deployment_name: target_config["deployment_name"],
16
+ name: target_config["container"],
17
+ )
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ module Kcu
2
+ module Deploys
3
+ class GetTargetContainersConfig
4
+
5
+ extend LightService::Action
6
+ expects :config, :target_namespace, :image_config
7
+ promises :target_containers_config
8
+
9
+ executed do |c|
10
+ c.target_containers_config = catch(:config) do
11
+ if c.target_namespace.present?
12
+ c.config["deploys"].find do |conf|
13
+ throw(:config, conf) if conf["namespace"] == c.target_namespace
14
+ end
15
+
16
+ fail ArgumentError, "`#{c.target_namespace}` namespace is not configured"
17
+ end
18
+
19
+ throw :config, c.image_config
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ module Kcu
2
+ module Deploys
3
+ class SetImage
4
+
5
+ extend LightService::Action
6
+ expects :image_name, :target_containers
7
+
8
+ executed do |c|
9
+ c.target_containers.each do |container|
10
+ stdout_str, stderr_str, status = ExecShell.(
11
+ "kubectl",
12
+ "set",
13
+ "image",
14
+ "deployment",
15
+ container.deployment_name,
16
+ "--namespace" => container.namespace,
17
+ container.name => c.image_name,
18
+ )
19
+
20
+ if status.exitstatus.zero?
21
+ puts "Updated #{container.namespace} deployment " +
22
+ "#{container.deployment_name} #{container.name} to " +
23
+ "#{c.image_name}"
24
+ else
25
+ puts stderr_str
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module Kcu
2
+ module Deploys
3
+ class SetTargetNamespace
4
+
5
+ extend LightService::Action
6
+ expects :image_config, :target_namespace
7
+
8
+ executed do |c|
9
+ next c if c.target_namespace.present?
10
+ c.target_namespace = c.image_config["namespace"]
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module Kcu
2
+ class ExecShell
3
+
4
+ def self.call(*args)
5
+ command_parts = []
6
+ args.each do |arg|
7
+ if arg.is_a?(Hash)
8
+ arg.each do |key, value|
9
+ command_parts << [key, value].join("=")
10
+ end
11
+ else
12
+ command_parts << arg
13
+ end
14
+ end
15
+
16
+ command = command_parts.join(" ")
17
+
18
+ Open3.capture3(command)
19
+ end
20
+
21
+ end
22
+ end
@@ -7,16 +7,14 @@ module Kcu
7
7
  promises :secret_json
8
8
 
9
9
  executed do |c|
10
- shell_command = [
10
+ stdout_str, stderr_str, status = ExecShell.(
11
11
  "kubectl",
12
12
  "get",
13
13
  "secret",
14
14
  c.resource_name,
15
- "--namespace=#{c.resource_namespace}",
16
- "--output=json",
17
- ].join(" ")
18
-
19
- stdout_str, stderr_str, status = Open3.capture3(shell_command)
15
+ "--namespace" => c.resource_namespace,
16
+ "--output" => "json",
17
+ )
20
18
 
21
19
  c.secret_json = JSON.parse(stdout_str)
22
20
  end
@@ -16,16 +16,15 @@ module Kcu
16
16
  c.entry_name => c.encoded_entry_value,
17
17
  },
18
18
  }.to_json
19
- shell_command = [
19
+
20
+ stdout_str, stderr_str, status = ExecShell.(
20
21
  "kubectl",
21
22
  "patch",
22
23
  "secret",
23
24
  c.resource_name,
24
- "--namespace=#{c.resource_namespace}",
25
- ["--patch", "'#{patch_json}'"].join("="),
26
- ].join(" ")
27
-
28
- stdout_str, stderr_str, status = Open3.capture3(shell_command)
25
+ "--namespace" => c.resource_namespace,
26
+ "--patch" => "'#{patch_json}'",
27
+ )
29
28
 
30
29
  puts stdout_str
31
30
  end
data/lib/kcu/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kcu
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/kcu.rb CHANGED
@@ -1,25 +1,40 @@
1
+ require "active_support/core_ext/object/blank"
1
2
  require "awesome_print"
2
3
  require "base64"
3
4
  require "commander"
5
+ require "dry-initializer"
6
+ require "git"
4
7
  require "json"
5
8
  require "light-service"
6
9
  require "open3"
10
+ require "to_regexp"
7
11
 
8
12
  module Kcu
9
13
  end
10
14
 
11
15
  require "kcu/version"
12
16
  require "kcu/summary"
17
+ require "kcu/models/container"
18
+ require "kcu/services/exec_shell"
13
19
  require "kcu/services/get_resource_namespace_and_name"
14
20
  require "kcu/services/secrets/get_json"
15
21
  require "kcu/services/secrets/decode_data"
16
22
  require "kcu/services/secrets/get_entry_value"
17
23
  require "kcu/services/secrets/encode_entry_value"
18
24
  require "kcu/services/secrets/set_entry_value"
19
- require "kcu/services/secrets/get_entry_value"
25
+ require "kcu/services/deployments/restart_deployment"
26
+ require "kcu/services/deploys/get_config"
27
+ require "kcu/services/deploys/set_target_namespace"
28
+ require "kcu/services/deploys/get_image_config"
29
+ require "kcu/services/deploys/gen_image_name"
30
+ require "kcu/services/deploys/set_image"
31
+ require "kcu/services/deploys/get_target_containers_config"
32
+ require "kcu/services/deploys/get_target_containers"
20
33
  require "kcu/actions/list_secret_action"
21
34
  require "kcu/actions/get_secret_action"
22
35
  require "kcu/actions/set_secret_action"
36
+ require "kcu/actions/restart_deployment_action"
37
+ require "kcu/actions/deploy_action"
23
38
  require "kcu/client"
24
39
 
25
40
  Kcu.new.run if $0 == __FILE__
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kcu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ramon Tayag
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-26 00:00:00.000000000 Z
11
+ date: 2017-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: awesome_print
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '4.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-initializer
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.3'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: light-service
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,34 @@ dependencies:
52
80
  - - '='
53
81
  - !ruby/object:Gem::Version
54
82
  version: 0.8.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: git
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: to_regexp
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 0.2.1
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 0.2.1
55
111
  - !ruby/object:Gem::Dependency
56
112
  name: bundler
57
113
  requirement: !ruby/object:Gem::Requirement
@@ -94,10 +150,25 @@ dependencies:
94
150
  - - "~>"
95
151
  - !ruby/object:Gem::Version
96
152
  version: '3.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: timecop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
97
167
  description:
98
168
  email:
99
169
  - ramon@tayag.net
100
- executables: []
170
+ executables:
171
+ - kcu
101
172
  extensions: []
102
173
  extra_rdoc_files: []
103
174
  files:
@@ -117,10 +188,22 @@ files:
117
188
  - bin/setup
118
189
  - kcu.gemspec
119
190
  - lib/kcu.rb
191
+ - lib/kcu/actions/deploy_action.rb
120
192
  - lib/kcu/actions/get_secret_action.rb
121
193
  - lib/kcu/actions/list_secret_action.rb
194
+ - lib/kcu/actions/restart_deployment_action.rb
122
195
  - lib/kcu/actions/set_secret_action.rb
123
196
  - lib/kcu/client.rb
197
+ - lib/kcu/models/container.rb
198
+ - lib/kcu/services/deployments/restart_deployment.rb
199
+ - lib/kcu/services/deploys/gen_image_name.rb
200
+ - lib/kcu/services/deploys/get_config.rb
201
+ - lib/kcu/services/deploys/get_image_config.rb
202
+ - lib/kcu/services/deploys/get_target_containers.rb
203
+ - lib/kcu/services/deploys/get_target_containers_config.rb
204
+ - lib/kcu/services/deploys/set_image.rb
205
+ - lib/kcu/services/deploys/set_target_namespace.rb
206
+ - lib/kcu/services/exec_shell.rb
124
207
  - lib/kcu/services/get_resource_namespace_and_name.rb
125
208
  - lib/kcu/services/secrets/decode_data.rb
126
209
  - lib/kcu/services/secrets/encode_entry_value.rb