kcu 0.2.0 → 0.3.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
  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