kubec 0.1.0 → 0.2.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 +4 -4
- data/.gitignore +2 -0
- data/.overcommit.yml +30 -0
- data/README.md +3 -5
- data/exe/kubec +5 -0
- data/kubec.gemspec +8 -3
- data/lib/Kubeconfig +4 -0
- data/lib/kubec/application.rb +110 -0
- data/lib/kubec/deploy.rb +1 -0
- data/lib/kubec/dsl/env.rb +14 -0
- data/lib/kubec/dsl/kubernetes.rb +16 -0
- data/lib/kubec/dsl/paths.rb +16 -0
- data/lib/kubec/dsl/stages.rb +32 -0
- data/lib/kubec/dsl.rb +14 -0
- data/lib/kubec/environment.rb +16 -0
- data/lib/kubec/install.rb +1 -0
- data/lib/kubec/kubernetes/config.rb +45 -0
- data/lib/kubec/kubernetes/container.rb +31 -0
- data/lib/kubec/kubernetes/deployment.rb +17 -0
- data/lib/kubec/kubernetes/has_attribute.rb +22 -0
- data/lib/kubec/kubernetes/metadata.rb +25 -0
- data/lib/kubec/kubernetes/service.rb +35 -0
- data/lib/kubec/kubernetes/template.rb +29 -0
- data/lib/kubec/kubernetes.rb +71 -0
- data/lib/kubec/setup.rb +10 -0
- data/lib/kubec/status/base.rb +52 -0
- data/lib/kubec/status/deployment.rb +54 -0
- data/lib/kubec/status/pod.rb +57 -0
- data/lib/kubec/status/service.rb +48 -0
- data/lib/kubec/status.rb +1 -0
- data/lib/kubec/tasks/deploy.rake +25 -0
- data/lib/kubec/tasks/install.rake +11 -0
- data/lib/kubec/tasks/status.rake +26 -0
- data/lib/kubec/templates/Kubeconfig +6 -0
- data/lib/kubec/templates/config/kubec/production.rb +0 -0
- data/lib/kubec/templates/config/kubec/staging.rb +0 -0
- data/lib/kubec/templates/config/kubec.rb +0 -0
- data/lib/kubec/utils/helper.rb +12 -0
- data/lib/kubec/utils/humanize_time.rb +42 -0
- data/lib/kubec/utils.rb +7 -0
- data/lib/kubec/version.rb +1 -1
- data/lib/kubec.rb +15 -1
- metadata +107 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e29547dc53808d55661f20349483c90c709d8ae4
|
4
|
+
data.tar.gz: c2de23b6dbc3444b4ec3d5017ad1e31f227416e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27ac3b15f987988bc7ec555a98824c3e7377aa386eae3aab00b36b166fad84f8c6ec7ba8acaea572ca295e52acc4dc733dce214e53045fe961c58c94e37f1c6b
|
7
|
+
data.tar.gz: 2ce1d12f2f50f085e1121ade09320841308545add1eaa5921e843740d553090e6316fe5754276543e421302edced92a21b96c1fec7b35f2d7ce3d76bd5556385
|
data/.gitignore
CHANGED
data/.overcommit.yml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
## Use this file to configure the Overcommit hooks you wish to use. This will
|
2
|
+
# extend the default configuration defined in:
|
3
|
+
# https://github.com/brigade/overcommit/blob/master/config/default.yml
|
4
|
+
#
|
5
|
+
# At the topmost level of this YAML file is a key representing type of hook
|
6
|
+
# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
|
7
|
+
# customize each hook, such as whether to only run it on certain files (via
|
8
|
+
# `include`), whether to only display output if it fails (via `quiet`), etc.
|
9
|
+
#
|
10
|
+
# For a complete list of hooks, see:
|
11
|
+
# https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook
|
12
|
+
#
|
13
|
+
# For a complete list of options that you can use to customize hooks, see:
|
14
|
+
# https://github.com/brigade/overcommit#configuration
|
15
|
+
#
|
16
|
+
# Uncomment the following lines to make the configuration take effect.
|
17
|
+
|
18
|
+
PreCommit:
|
19
|
+
AuthorName:
|
20
|
+
enabled: false
|
21
|
+
RuboCop:
|
22
|
+
enabled: true
|
23
|
+
on_warn: fail # Treat all warnings as failures
|
24
|
+
|
25
|
+
TrailingWhitespace:
|
26
|
+
enabled: true
|
27
|
+
|
28
|
+
PostCheckout:
|
29
|
+
IndexTags:
|
30
|
+
enabled: true # Generate a tags file with `ctags` each time HEAD changes
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Kubec
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/kubec) [](https://travis-ci.org/5xRuby/kubec) [](https://codeclimate.com/github/5xRuby/kubec/test_coverage) [](https://codeclimate.com/github/5xRuby/kubec/maintainability)
|
4
4
|
|
5
|
-
|
5
|
+
Kubec is a utility for generate kubernetes config and deploy.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -22,8 +22,6 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
TODO: Write usage instructions here
|
26
|
-
|
27
25
|
## Development
|
28
26
|
|
29
27
|
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.
|
@@ -32,4 +30,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
30
|
|
33
31
|
## Contributing
|
34
32
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
33
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/5xruby/kubec.
|
data/exe/kubec
ADDED
data/kubec.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'kubec/version'
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'kubec'
|
7
7
|
spec.version = Kubec::VERSION
|
8
|
-
spec.authors = %w[
|
8
|
+
spec.authors = %w[5xRuby Aotokitsuruya]
|
9
9
|
spec.email = %w[rubygems@5xruby.tw contact@frost.tw]
|
10
10
|
|
11
11
|
spec.summary = 'Kubec is a utility for generate kubernetes config ' \
|
@@ -21,8 +21,13 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ['lib']
|
23
23
|
|
24
|
+
spec.add_dependency 'colorize'
|
25
|
+
spec.add_dependency 'hirb'
|
26
|
+
spec.add_dependency 'rake', '~> 10.0'
|
27
|
+
|
24
28
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
25
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
26
29
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
30
|
+
spec.add_development_dependency 'rubocop', '~> 0.49.0'
|
31
|
+
spec.add_development_dependency 'overcommit'
|
32
|
+
spec.add_development_dependency 'simplecov'
|
28
33
|
end
|
data/lib/Kubeconfig
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
module Kubec
|
2
|
+
# Kubec Application
|
3
|
+
class Application < Rake::Application
|
4
|
+
DEFAULT_KUBECFILES = [
|
5
|
+
'Kubeconfig',
|
6
|
+
'kubeconfig',
|
7
|
+
'Kubeconfig.rb',
|
8
|
+
'kubeconfig.rb'
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
def self.config_exist?
|
12
|
+
DEFAULT_KUBECFILES.map { |f| File.exist?(f) }.reduce(:|)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
@rakefiles = DEFAULT_KUBECFILES.dup << default_kubeconfig
|
18
|
+
end
|
19
|
+
|
20
|
+
def name
|
21
|
+
'kubec'
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
Rake.application = self
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def top_level_tasks
|
30
|
+
# rubocop:disable Metrics/LineLength
|
31
|
+
return @top_level_tasks if tasks_without_stage_dependency.include?(@top_level_tasks.first)
|
32
|
+
# rubocop:enable Metrics/LineLength
|
33
|
+
|
34
|
+
@top_level_tasks.unshift(ensure_environment.to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def ensure_environment
|
40
|
+
Rake::Task.define_task(:ensure_environment) do
|
41
|
+
puts 'Kubeconfig isn\'t install or stage not configured'
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def tasks_without_stage_dependency
|
47
|
+
stages + default_tasks
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_tasks
|
51
|
+
%w[install]
|
52
|
+
end
|
53
|
+
|
54
|
+
def handle_options
|
55
|
+
setup_options
|
56
|
+
|
57
|
+
OptionParser.new do |opts|
|
58
|
+
opts.on_tail('-h', '--help', '-H', 'Display this help message.') do
|
59
|
+
puts opts
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
standard_rake_options.each { |args| opts.on(*args) }
|
64
|
+
opts.environment('KUBEOPT')
|
65
|
+
end.parse!
|
66
|
+
end
|
67
|
+
|
68
|
+
def sort_options(options)
|
69
|
+
supported_options = %w[tasks]
|
70
|
+
|
71
|
+
options.select! do |(switch, *)|
|
72
|
+
switch =~ /--#{Regexp.union(supported_options)}/
|
73
|
+
end
|
74
|
+
|
75
|
+
super.push(debug, version)
|
76
|
+
end
|
77
|
+
|
78
|
+
def setup_options
|
79
|
+
options.rakelib = ['rakelib']
|
80
|
+
options.debug = false
|
81
|
+
options.trace_output = STDERR
|
82
|
+
end
|
83
|
+
|
84
|
+
def default_kubeconfig
|
85
|
+
File.expand_path('../../Kubeconfig', __FILE__)
|
86
|
+
end
|
87
|
+
|
88
|
+
def debug
|
89
|
+
[
|
90
|
+
'--[no-]debug', '-D',
|
91
|
+
'Display debug information',
|
92
|
+
lambda do |value|
|
93
|
+
options.debug = value
|
94
|
+
end
|
95
|
+
]
|
96
|
+
end
|
97
|
+
|
98
|
+
def version
|
99
|
+
[
|
100
|
+
'--version', '-V',
|
101
|
+
'Display the program version.',
|
102
|
+
lambda do |_value|
|
103
|
+
puts "Kubec Version: #{Kubec::VERSION} "\
|
104
|
+
"(Rake Version: #{Rake::VERSION})"
|
105
|
+
exit
|
106
|
+
end
|
107
|
+
]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/kubec/deploy.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
load File.expand_path('../tasks/deploy.rake', __FILE__)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kubec
|
4
|
+
module DSL
|
5
|
+
# Stage
|
6
|
+
module Stages
|
7
|
+
RESERVED_NAMES = %w[deploy install status logs].freeze
|
8
|
+
|
9
|
+
def stages
|
10
|
+
names = Dir[stage_definitions].map { |f| File.basename(f, '.rb') }
|
11
|
+
assert_valid_stage_names(names)
|
12
|
+
names
|
13
|
+
end
|
14
|
+
|
15
|
+
def stage_definitions
|
16
|
+
stage_config_path.join('*.rb')
|
17
|
+
end
|
18
|
+
|
19
|
+
def stage_set?
|
20
|
+
!fetch(:stage, nil).nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_valid_stage_names(names)
|
24
|
+
invalid = names.find { |n| RESERVED_NAMES.include?(n) }
|
25
|
+
return if invalid.nil?
|
26
|
+
|
27
|
+
# TODO: I18n Support
|
28
|
+
raise "Invalid stage name #{invalid}.rb"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/kubec/dsl.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kubec
|
4
|
+
# Environment
|
5
|
+
class Environment < Hash
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
def fetch(key, default = nil)
|
9
|
+
self[key.to_sym] || default
|
10
|
+
end
|
11
|
+
|
12
|
+
def set(key, value)
|
13
|
+
self[key.to_sym] = value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
load File.expand_path('../tasks/install.rake', __FILE__)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Kubec
|
2
|
+
class Kubernetes
|
3
|
+
# :nodoc:
|
4
|
+
class Config < Hash
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
def_delegators :metadata, :labels, :label
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def api_version(version = nil)
|
13
|
+
return @api_version if version.nil?
|
14
|
+
@api_version = version
|
15
|
+
end
|
16
|
+
|
17
|
+
def kind
|
18
|
+
name.split('::').last
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(name, &block)
|
23
|
+
@name = name.to_sym
|
24
|
+
prepare
|
25
|
+
instance_eval(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def spec
|
29
|
+
self[:spec]
|
30
|
+
end
|
31
|
+
|
32
|
+
def metadata(&block)
|
33
|
+
return self[:metadata] unless block_given?
|
34
|
+
self[:metadata].instance_eval(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def prepare
|
38
|
+
self[:apiVersion] = self.class.api_version
|
39
|
+
self[:kind] = self.class.kind
|
40
|
+
self[:metadata] = Metadata.new(@name)
|
41
|
+
self[:spec] = {}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kubec
|
2
|
+
class Kubernetes
|
3
|
+
# :nodoc:
|
4
|
+
class Container < Hash
|
5
|
+
include HasAttribute
|
6
|
+
|
7
|
+
attribute :image
|
8
|
+
attribute :name
|
9
|
+
attribute :ports
|
10
|
+
|
11
|
+
def initialize(name, &block)
|
12
|
+
self[:name] = name
|
13
|
+
instance_eval(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: Add object to check fields
|
17
|
+
def port(container_port, host_port = nil,
|
18
|
+
ip: nil, name: nil, protocol: nil)
|
19
|
+
self[:ports] ||= []
|
20
|
+
port = {
|
21
|
+
containerPort: container_port,
|
22
|
+
hostPort: host_port,
|
23
|
+
hostIP: ip,
|
24
|
+
name: name,
|
25
|
+
protocol: protocol
|
26
|
+
}.compact
|
27
|
+
self[:ports].push port
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Kubec
|
2
|
+
class Kubernetes
|
3
|
+
# :nodoc:
|
4
|
+
class Deployment < Config
|
5
|
+
api_version 'extensions/v1beta1'
|
6
|
+
|
7
|
+
def replicas(size)
|
8
|
+
spec[:replicas] = size.to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
def template(&block)
|
12
|
+
spec[:template] ||= Template.new
|
13
|
+
spec[:template].instance_eval(&block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kubec
|
2
|
+
class Kubernetes
|
3
|
+
# :nodoc:
|
4
|
+
module HasAttribute
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
# :nodoc:
|
10
|
+
module ClassMethods
|
11
|
+
def attribute(name)
|
12
|
+
name = name.to_sym
|
13
|
+
define_method(name) do |value|
|
14
|
+
return self[name] if value.nil?
|
15
|
+
self[name] = value
|
16
|
+
end
|
17
|
+
define_method("#{name}=") { |value| self[name] = value }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kubec
|
2
|
+
class Kubernetes
|
3
|
+
# :nodoc:
|
4
|
+
class Metadata < Hash
|
5
|
+
def initialize(name = nil)
|
6
|
+
self[:name] = name unless name.nil?
|
7
|
+
self[:namespace] = fetch(:stage, :staging)
|
8
|
+
end
|
9
|
+
|
10
|
+
def label(key, value)
|
11
|
+
self['labels'] ||= {}
|
12
|
+
self['labels'][key] = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def labels=(labels = nil)
|
16
|
+
self['labels'] ||= {}
|
17
|
+
return self['labels'] if labels.nil?
|
18
|
+
# TODO: Check labels is valid
|
19
|
+
self['labels'] = labels
|
20
|
+
end
|
21
|
+
|
22
|
+
alias labels labels=
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Kubec
|
2
|
+
class Kubernetes
|
3
|
+
# :nodoc:
|
4
|
+
class Service < Config
|
5
|
+
api_version 'v1'
|
6
|
+
|
7
|
+
def node_port
|
8
|
+
spec[:type] = 'NodePort'
|
9
|
+
end
|
10
|
+
|
11
|
+
def load_balancer(ip: nil)
|
12
|
+
spec[:type] = 'LoadBalancer'
|
13
|
+
spec[:loadBalancerIP] = ip unless ip.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
def port(port, target = nil)
|
17
|
+
spec[:ports] ||= []
|
18
|
+
target ||= port
|
19
|
+
spec[:ports].push port: port, targetPort: target
|
20
|
+
end
|
21
|
+
|
22
|
+
def select(key, value)
|
23
|
+
spec[:selector] ||= {}
|
24
|
+
spec[:selector][key] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
def selector=(labels)
|
28
|
+
# TODO: Check labels type
|
29
|
+
spec[:selector] = labels
|
30
|
+
end
|
31
|
+
|
32
|
+
alias selector selector=
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kubec
|
2
|
+
class Kubernetes
|
3
|
+
# :nodoc:
|
4
|
+
class Template < Hash
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :metadata, :labels, :label
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
self[:metadata] = Metadata.new
|
11
|
+
self[:spec] = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def metadata(&block)
|
15
|
+
return self[:metadata] unless block_given?
|
16
|
+
self[:metadata].instance_eval(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def spec
|
20
|
+
self[:spec]
|
21
|
+
end
|
22
|
+
|
23
|
+
def container(name, &block)
|
24
|
+
spec[:containers] ||= []
|
25
|
+
spec[:containers].push Container.new(name, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kubec
|
4
|
+
# Kubernetes
|
5
|
+
class Kubernetes
|
6
|
+
autoload :Config, 'kubec/kubernetes/config'
|
7
|
+
autoload :Template, 'kubec/kubernetes/template'
|
8
|
+
autoload :Service, 'kubec/kubernetes/service'
|
9
|
+
autoload :Deployment, 'kubec/kubernetes/deployment'
|
10
|
+
autoload :Metadata, 'kubec/kubernetes/metadata'
|
11
|
+
autoload :Spec, 'kubec/kubernetes/spec'
|
12
|
+
autoload :Container, 'kubec/kubernetes/container'
|
13
|
+
|
14
|
+
autoload :HasAttribute, 'kubec/kubernetes/has_attribute'
|
15
|
+
|
16
|
+
include Singleton
|
17
|
+
|
18
|
+
APPLYABLE_TYPES = %i[service deployment].freeze
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def apply(type)
|
22
|
+
# TODO: Raise an error
|
23
|
+
return unless APPLYABLE_TYPES.include?(type.to_sym)
|
24
|
+
return debug(type) if Rake.application.options.debug
|
25
|
+
# TODO: Replace with RESTful API
|
26
|
+
IO.popen('kubectl apply -f -', 'r+') do |io|
|
27
|
+
io.write convert_to_json(instance.send(type))
|
28
|
+
io.close_write
|
29
|
+
puts io.gets
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def debug(type)
|
34
|
+
return unless APPLYABLE_TYPES.include?(type.to_sym)
|
35
|
+
puts JSON.pretty_generate(instance.send(type))
|
36
|
+
end
|
37
|
+
|
38
|
+
def ensure_namespace
|
39
|
+
return if Rake.application.options.debug
|
40
|
+
stage = fetch(:stage, :staging)
|
41
|
+
|
42
|
+
# TODO: Replace with RESTful API
|
43
|
+
`kubectl get ns #{stage} 2>&1`
|
44
|
+
`kubectl create ns #{stage}` unless $CHILD_STATUS.success?
|
45
|
+
end
|
46
|
+
|
47
|
+
def convert_to_json(items)
|
48
|
+
{
|
49
|
+
apiVersion: 'v1',
|
50
|
+
items: items,
|
51
|
+
kind: 'List'
|
52
|
+
}.to_json
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize
|
57
|
+
@services = []
|
58
|
+
@deployments = []
|
59
|
+
end
|
60
|
+
|
61
|
+
def service(name = nil, &block)
|
62
|
+
return @services if name.nil?
|
63
|
+
@services << Kubernetes::Service.new(name, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def deployment(name = nil, &block)
|
67
|
+
return @deployments if name.nil?
|
68
|
+
@deployments << Kubernetes::Deployment.new(name, &block)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/kubec/setup.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Kubec
|
2
|
+
# :nodoc:
|
3
|
+
module Status
|
4
|
+
autoload :Printer, 'kubec/status/printer'
|
5
|
+
autoload :Service, 'kubec/status/service'
|
6
|
+
autoload :Deployment, 'kubec/status/deployment'
|
7
|
+
autoload :Pod, 'kubec/status/pod'
|
8
|
+
|
9
|
+
# :nodoc:
|
10
|
+
class Base
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def fields(fields = nil)
|
15
|
+
return @fields if fields.nil?
|
16
|
+
@fields = fields
|
17
|
+
end
|
18
|
+
|
19
|
+
def print
|
20
|
+
if fields.nil?
|
21
|
+
ptus Hirb::Helpers::AutoTable.render(new)
|
22
|
+
else
|
23
|
+
puts Hirb::Helpers::AutoTable.render(new, fields: fields)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@type = self.class.name.split('::').last.downcase
|
30
|
+
@result = `kubectl -n #{fetch(:stage, :staging)} get #{@type} -o json`
|
31
|
+
@success = $CHILD_STATUS.success?
|
32
|
+
@items = []
|
33
|
+
|
34
|
+
prepare
|
35
|
+
end
|
36
|
+
|
37
|
+
def each(&_block)
|
38
|
+
return unless @success
|
39
|
+
@items.each do |item|
|
40
|
+
yield self.class.const_get('Item').new(item)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def prepare
|
47
|
+
return unless @success
|
48
|
+
@items = JSON.parse(@result).dig('items') || []
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Kubec
|
2
|
+
module Status
|
3
|
+
# :nodoc:
|
4
|
+
class Deployment < Base
|
5
|
+
fields ['Name', 'Desire', 'Current', 'Up to date', 'Available', 'Age']
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
class Item < Hash
|
9
|
+
FIELDS = %i[name desire current up_to_date available age].freeze
|
10
|
+
|
11
|
+
attr_reader :spec, :metadata, :status
|
12
|
+
|
13
|
+
def initialize(data)
|
14
|
+
@data = data
|
15
|
+
@metadata = data.dig('metadata')
|
16
|
+
@spec = data.dig('spec')
|
17
|
+
@status = data.dig('status')
|
18
|
+
|
19
|
+
FIELDS.each { |field| send("setup_#{field}") }
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def setup_name
|
25
|
+
self['Name'] = metadata['name']
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_desire
|
29
|
+
self['Desire'] = spec['replicas'] || 1
|
30
|
+
end
|
31
|
+
|
32
|
+
def setup_current
|
33
|
+
self['Current'] = status['readyReplicas'] || 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def setup_up_to_date
|
37
|
+
self['Up to date'] = status['updatedReplicas'] || 0
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup_available
|
41
|
+
self['Available'] = status['availableReplicas'] || 0
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup_age
|
45
|
+
created_at = DateTime.parse(metadata['creationTimestamp']).to_time
|
46
|
+
secs = (Time.now - created_at).ceil
|
47
|
+
self['Age'] =
|
48
|
+
Utils::HumanizeTime
|
49
|
+
.humanize(secs, short: true, join: false).first
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Kubec
|
2
|
+
module Status
|
3
|
+
# :nodoc:
|
4
|
+
class Pod < Base
|
5
|
+
fields %w[Name Ready Status Restarts Age]
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
class Item < Hash
|
9
|
+
FIELDS = %i[name ready status restarts age].freeze
|
10
|
+
|
11
|
+
attr_reader :spec, :metadata, :status, :containers
|
12
|
+
|
13
|
+
def initialize(data)
|
14
|
+
@data = data
|
15
|
+
@metadata = data.dig('metadata')
|
16
|
+
@spec = data.dig('spec')
|
17
|
+
@status = data.dig('status')
|
18
|
+
@containers = data.dig('status', 'containerStatuses')
|
19
|
+
|
20
|
+
FIELDS.each { |field| send("setup_#{field}") }
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def setup_name
|
26
|
+
self['Name'] = metadata['name']
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup_ready
|
30
|
+
total = containers.size
|
31
|
+
ready = containers.select do |item|
|
32
|
+
item['state'].key?('running')
|
33
|
+
end.size
|
34
|
+
self['Ready'] = "#{ready}/#{total}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def setup_status
|
38
|
+
self['Status'] = status['phase']
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup_restarts
|
42
|
+
self['Restarts'] = containers.map do |c|
|
43
|
+
c['restartCount'].to_i
|
44
|
+
end.sum
|
45
|
+
end
|
46
|
+
|
47
|
+
def setup_age
|
48
|
+
created_at = DateTime.parse(status['startTime']).to_time
|
49
|
+
secs = (Time.now - created_at).ceil
|
50
|
+
self['Age'] =
|
51
|
+
Utils::HumanizeTime
|
52
|
+
.humanize(secs, short: true, join: false).first
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Kubec
|
2
|
+
module Status
|
3
|
+
# :nodoc:
|
4
|
+
class Service < Base
|
5
|
+
fields ['Name', 'Cluster IP', 'Ports', 'Selector']
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
class Item < Hash
|
9
|
+
FIELDS = %i[name cluster_ip ports selector].freeze
|
10
|
+
|
11
|
+
attr_reader :spec, :metadata
|
12
|
+
|
13
|
+
def initialize(data)
|
14
|
+
@data = data
|
15
|
+
@metadata = data.dig('metadata')
|
16
|
+
@spec = data.dig('spec')
|
17
|
+
|
18
|
+
FIELDS.each { |field| send("setup_#{field}") }
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def setup_name
|
24
|
+
self['Name'] = metadata['name']
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_cluster_ip
|
28
|
+
self['Cluster IP'] = spec['clusterIP']
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_ports
|
32
|
+
self['Ports'] = spec['ports'].map do |port|
|
33
|
+
target = port['nodePort'] || port['targetPort']
|
34
|
+
"#{port['port']}:#{target}/#{port['protocol']}"
|
35
|
+
end.join(', ')
|
36
|
+
end
|
37
|
+
|
38
|
+
def setup_selector
|
39
|
+
self['Selector'] =
|
40
|
+
spec['selector']
|
41
|
+
.map(&:to_a)
|
42
|
+
.map { |pair| pair.join('=') }
|
43
|
+
.join(', ')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/kubec/status.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
load File.expand_path('../tasks/status.rake', __FILE__)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
namespace :deploy do
|
2
|
+
task :namespace do
|
3
|
+
Kubec::Kubernetes.ensure_namespace
|
4
|
+
end
|
5
|
+
|
6
|
+
# TODO: Add support for real kubectl
|
7
|
+
desc 'Apply Deployment to Kubernetes'
|
8
|
+
task :deployments do
|
9
|
+
Kubec::Utils::Helper.header 'Starting apply deployments'
|
10
|
+
Kubec::Kubernetes.apply(:deployment)
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Apply Service to Kubernetes'
|
14
|
+
task :services do
|
15
|
+
Kubec::Utils::Helper.header 'Starting apply services'
|
16
|
+
Kubec::Kubernetes.apply(:service)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Deploy to Kubernetes'
|
21
|
+
task deploy: [
|
22
|
+
'deploy:namespace',
|
23
|
+
'deploy:deployments',
|
24
|
+
'deploy:services'
|
25
|
+
]
|
@@ -0,0 +1,26 @@
|
|
1
|
+
namespace :status do
|
2
|
+
desc 'Show service status'
|
3
|
+
task :service do
|
4
|
+
Kubec::Utils::Helper.header 'Service Status'
|
5
|
+
Kubec::Status::Service.print
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Show deployment status'
|
9
|
+
task :deployment do
|
10
|
+
Kubec::Utils::Helper.header 'Deployment Status'
|
11
|
+
Kubec::Status::Deployment.print
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Show pod status'
|
15
|
+
task :pod do
|
16
|
+
Kubec::Utils::Helper.header 'Pod Status'
|
17
|
+
Kubec::Status::Pod.print
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Show deploy status'
|
22
|
+
task status: [
|
23
|
+
'status:service',
|
24
|
+
'status:deployment',
|
25
|
+
'status:pod'
|
26
|
+
]
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Kubec
|
2
|
+
module Utils
|
3
|
+
# :nodoc:
|
4
|
+
module HumanizeTime
|
5
|
+
PAIRS = [
|
6
|
+
[60, :seconds],
|
7
|
+
[60, :minutes],
|
8
|
+
[24, :hours],
|
9
|
+
[1000, :days]
|
10
|
+
].freeze
|
11
|
+
|
12
|
+
SHORT = {
|
13
|
+
seocnds: 's',
|
14
|
+
minutes: 'm',
|
15
|
+
hours: 'h',
|
16
|
+
days: 'd'
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def humanize(secs, short: false, join: true)
|
21
|
+
list = convert(secs).map do |(count, name)|
|
22
|
+
if short
|
23
|
+
"#{count}#{SHORT[name]}"
|
24
|
+
else
|
25
|
+
"#{count} #{name}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
return list unless join
|
29
|
+
list.join(' ')
|
30
|
+
end
|
31
|
+
|
32
|
+
def convert(secs)
|
33
|
+
PAIRS.dup.map do |count, name|
|
34
|
+
next unless secs > 0
|
35
|
+
secs, n = secs.divmod(count)
|
36
|
+
[n, name]
|
37
|
+
end.compact.reverse
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/kubec/utils.rb
ADDED
data/lib/kubec/version.rb
CHANGED
data/lib/kubec.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'json'
|
3
|
+
require 'forwardable'
|
4
|
+
require 'pathname'
|
5
|
+
require 'singleton'
|
6
|
+
require 'hirb'
|
7
|
+
require 'colorize'
|
8
|
+
require 'English'
|
9
|
+
|
1
10
|
require 'kubec/version'
|
2
11
|
|
3
12
|
# Kuberentes Config Tool
|
4
13
|
module Kubec
|
5
|
-
|
14
|
+
autoload :Application, 'kubec/application'
|
15
|
+
autoload :Environment, 'kubec/environment'
|
16
|
+
autoload :Kubernetes, 'kubec/kubernetes'
|
17
|
+
autoload :DSL, 'kubec/dsl'
|
18
|
+
autoload :Status, 'kubec/status/base'
|
19
|
+
autoload :Utils, 'kubec/utils'
|
6
20
|
end
|
metadata
CHANGED
@@ -1,30 +1,44 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
-
|
7
|
+
- 5xRuby
|
8
|
+
- Aotokitsuruya
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-01-
|
12
|
+
date: 2018-01-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: colorize
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
21
|
-
type: :
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: hirb
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: rake
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -32,13 +46,27 @@ dependencies:
|
|
32
46
|
- - "~>"
|
33
47
|
- !ruby/object:Gem::Version
|
34
48
|
version: '10.0'
|
35
|
-
type: :
|
49
|
+
type: :runtime
|
36
50
|
prerelease: false
|
37
51
|
version_requirements: !ruby/object:Gem::Requirement
|
38
52
|
requirements:
|
39
53
|
- - "~>"
|
40
54
|
- !ruby/object:Gem::Version
|
41
55
|
version: '10.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: bundler
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1.16'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.16'
|
42
70
|
- !ruby/object:Gem::Dependency
|
43
71
|
name: rspec
|
44
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,23 +87,53 @@ dependencies:
|
|
59
87
|
requirements:
|
60
88
|
- - "~>"
|
61
89
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
90
|
+
version: 0.49.0
|
63
91
|
type: :development
|
64
92
|
prerelease: false
|
65
93
|
version_requirements: !ruby/object:Gem::Requirement
|
66
94
|
requirements:
|
67
95
|
- - "~>"
|
68
96
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
97
|
+
version: 0.49.0
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: overcommit
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: simplecov
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
70
126
|
description: Kubec is a utility for generate kubernetes config and deploy.
|
71
127
|
email:
|
72
128
|
- rubygems@5xruby.tw
|
73
129
|
- contact@frost.tw
|
74
|
-
executables:
|
130
|
+
executables:
|
131
|
+
- kubec
|
75
132
|
extensions: []
|
76
133
|
extra_rdoc_files: []
|
77
134
|
files:
|
78
135
|
- ".gitignore"
|
136
|
+
- ".overcommit.yml"
|
79
137
|
- ".rspec"
|
80
138
|
- ".rubocop.yml"
|
81
139
|
- ".travis.yml"
|
@@ -84,8 +142,43 @@ files:
|
|
84
142
|
- Rakefile
|
85
143
|
- bin/console
|
86
144
|
- bin/setup
|
145
|
+
- exe/kubec
|
87
146
|
- kubec.gemspec
|
147
|
+
- lib/Kubeconfig
|
88
148
|
- lib/kubec.rb
|
149
|
+
- lib/kubec/application.rb
|
150
|
+
- lib/kubec/deploy.rb
|
151
|
+
- lib/kubec/dsl.rb
|
152
|
+
- lib/kubec/dsl/env.rb
|
153
|
+
- lib/kubec/dsl/kubernetes.rb
|
154
|
+
- lib/kubec/dsl/paths.rb
|
155
|
+
- lib/kubec/dsl/stages.rb
|
156
|
+
- lib/kubec/environment.rb
|
157
|
+
- lib/kubec/install.rb
|
158
|
+
- lib/kubec/kubernetes.rb
|
159
|
+
- lib/kubec/kubernetes/config.rb
|
160
|
+
- lib/kubec/kubernetes/container.rb
|
161
|
+
- lib/kubec/kubernetes/deployment.rb
|
162
|
+
- lib/kubec/kubernetes/has_attribute.rb
|
163
|
+
- lib/kubec/kubernetes/metadata.rb
|
164
|
+
- lib/kubec/kubernetes/service.rb
|
165
|
+
- lib/kubec/kubernetes/template.rb
|
166
|
+
- lib/kubec/setup.rb
|
167
|
+
- lib/kubec/status.rb
|
168
|
+
- lib/kubec/status/base.rb
|
169
|
+
- lib/kubec/status/deployment.rb
|
170
|
+
- lib/kubec/status/pod.rb
|
171
|
+
- lib/kubec/status/service.rb
|
172
|
+
- lib/kubec/tasks/deploy.rake
|
173
|
+
- lib/kubec/tasks/install.rake
|
174
|
+
- lib/kubec/tasks/status.rake
|
175
|
+
- lib/kubec/templates/Kubeconfig
|
176
|
+
- lib/kubec/templates/config/kubec.rb
|
177
|
+
- lib/kubec/templates/config/kubec/production.rb
|
178
|
+
- lib/kubec/templates/config/kubec/staging.rb
|
179
|
+
- lib/kubec/utils.rb
|
180
|
+
- lib/kubec/utils/helper.rb
|
181
|
+
- lib/kubec/utils/humanize_time.rb
|
89
182
|
- lib/kubec/version.rb
|
90
183
|
homepage: https://kubec.5xruby.tw
|
91
184
|
licenses: []
|