kubec 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.overcommit.yml +30 -0
  4. data/README.md +3 -5
  5. data/exe/kubec +5 -0
  6. data/kubec.gemspec +8 -3
  7. data/lib/Kubeconfig +4 -0
  8. data/lib/kubec/application.rb +110 -0
  9. data/lib/kubec/deploy.rb +1 -0
  10. data/lib/kubec/dsl/env.rb +14 -0
  11. data/lib/kubec/dsl/kubernetes.rb +16 -0
  12. data/lib/kubec/dsl/paths.rb +16 -0
  13. data/lib/kubec/dsl/stages.rb +32 -0
  14. data/lib/kubec/dsl.rb +14 -0
  15. data/lib/kubec/environment.rb +16 -0
  16. data/lib/kubec/install.rb +1 -0
  17. data/lib/kubec/kubernetes/config.rb +45 -0
  18. data/lib/kubec/kubernetes/container.rb +31 -0
  19. data/lib/kubec/kubernetes/deployment.rb +17 -0
  20. data/lib/kubec/kubernetes/has_attribute.rb +22 -0
  21. data/lib/kubec/kubernetes/metadata.rb +25 -0
  22. data/lib/kubec/kubernetes/service.rb +35 -0
  23. data/lib/kubec/kubernetes/template.rb +29 -0
  24. data/lib/kubec/kubernetes.rb +71 -0
  25. data/lib/kubec/setup.rb +10 -0
  26. data/lib/kubec/status/base.rb +52 -0
  27. data/lib/kubec/status/deployment.rb +54 -0
  28. data/lib/kubec/status/pod.rb +57 -0
  29. data/lib/kubec/status/service.rb +48 -0
  30. data/lib/kubec/status.rb +1 -0
  31. data/lib/kubec/tasks/deploy.rake +25 -0
  32. data/lib/kubec/tasks/install.rake +11 -0
  33. data/lib/kubec/tasks/status.rake +26 -0
  34. data/lib/kubec/templates/Kubeconfig +6 -0
  35. data/lib/kubec/templates/config/kubec/production.rb +0 -0
  36. data/lib/kubec/templates/config/kubec/staging.rb +0 -0
  37. data/lib/kubec/templates/config/kubec.rb +0 -0
  38. data/lib/kubec/utils/helper.rb +12 -0
  39. data/lib/kubec/utils/humanize_time.rb +42 -0
  40. data/lib/kubec/utils.rb +7 -0
  41. data/lib/kubec/version.rb +1 -1
  42. data/lib/kubec.rb +15 -1
  43. metadata +107 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d080cd8618fd037e593cff3fd9483246d947e9b
4
- data.tar.gz: 5c7775cca3fa44bddf615f820b9b8671feb48dad
3
+ metadata.gz: e29547dc53808d55661f20349483c90c709d8ae4
4
+ data.tar.gz: c2de23b6dbc3444b4ec3d5017ad1e31f227416e2
5
5
  SHA512:
6
- metadata.gz: 39a8b7c2d514f96ac76a72c6f2720a16b50d0522b49b738026a3bb0488e98ddc72e9f6707e6f0d01cab97399c609db553cce0aacd0c8bc557c315a2a141da6f4
7
- data.tar.gz: c4740970b8e934ffa508f85d24e7a225dd1e58d8b3fc2c20135037e361c6344f295bb725635a3fe08012e2e6662156696026c6429d624f312e8c171bac86ae55
6
+ metadata.gz: 27ac3b15f987988bc7ec555a98824c3e7377aa386eae3aab00b36b166fad84f8c6ec7ba8acaea572ca295e52acc4dc733dce214e53045fe961c58c94e37f1c6b
7
+ data.tar.gz: 2ce1d12f2f50f085e1121ade09320841308545add1eaa5921e843740d553090e6316fe5754276543e421302edced92a21b96c1fec7b35f2d7ce3d76bd5556385
data/.gitignore CHANGED
@@ -9,3 +9,5 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ Gemfile.lock
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
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/kubec`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Gem Version](https://badge.fury.io/rb/kubec.svg)](https://badge.fury.io/rb/kubec) [![Build Status](https://travis-ci.org/5xRuby/kubec.svg?branch=master)](https://travis-ci.org/5xRuby/kubec) [![Test Coverage](https://api.codeclimate.com/v1/badges/8a4e6cf54745423e198b/test_coverage)](https://codeclimate.com/github/5xRuby/kubec/test_coverage) [![Maintainability](https://api.codeclimate.com/v1/badges/8a4e6cf54745423e198b/maintainability)](https://codeclimate.com/github/5xRuby/kubec/maintainability)
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
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/[USERNAME]/kubec.
33
+ Bug reports and pull requests are welcome on GitHub at https://github.com/5xruby/kubec.
data/exe/kubec ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'kubec'
4
+
5
+ Kubec::Application.new.run
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.5'
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,4 @@
1
+ #!/usr/bin/env kubec
2
+
3
+ include Kubec::DSL
4
+ require 'kubec/install'
@@ -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
@@ -0,0 +1 @@
1
+ load File.expand_path('../tasks/deploy.rake', __FILE__)
@@ -0,0 +1,14 @@
1
+ module Kubec
2
+ module DSL
3
+ # ENV
4
+ module Env
5
+ extend Forwardable
6
+
7
+ def_delegators :env, :fetch, :set
8
+
9
+ def env
10
+ Environment.instance
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kubec
4
+ module DSL
5
+ # :nodoc:
6
+ module Kubernetes
7
+ extend Forwardable
8
+
9
+ def_delegators :kubernetes, :service, :deployment
10
+
11
+ def kubernetes
12
+ Kubec::Kubernetes.instance
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Kubec
2
+ module DSL
3
+ # :nodoc:
4
+ module Paths
5
+ def stage_config_path
6
+ Pathname.new 'config/kubec'
7
+ end
8
+
9
+ def stack_config_path
10
+ Pathname.new 'config/kubec.rb'
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ extend Kubec::DSL
@@ -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,14 @@
1
+ require 'kubec/dsl/stages'
2
+ require 'kubec/dsl/paths'
3
+ require 'kubec/dsl/env'
4
+ require 'kubec/dsl/kubernetes'
5
+
6
+ module Kubec
7
+ # DSL
8
+ module DSL
9
+ include Env
10
+ include Paths
11
+ include Stages
12
+ include Kubernetes
13
+ end
14
+ end
@@ -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
@@ -0,0 +1,10 @@
1
+ include Kubec::DSL
2
+
3
+ stages.each do |stage|
4
+ Rake::Task.define_task(stage) do
5
+ set(:stage, stage)
6
+
7
+ load stage_config_path.join("#{stage}.rb")
8
+ load stack_config_path
9
+ end
10
+ end
@@ -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
@@ -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,11 @@
1
+ task :install do
2
+ template_path = File.expand_path('../../templates', __FILE__)
3
+
4
+ if Kubec::Application.config_exist?
5
+ warn '[SKIP] Kubec is already setup'
6
+ exit 1
7
+ end
8
+
9
+ FileUtils.cp_r("#{template_path}/.", '.')
10
+ puts 'Kubec Initialized'
11
+ end
@@ -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
+ ]
@@ -0,0 +1,6 @@
1
+ # Setup environement
2
+ require 'kubec/setup'
3
+
4
+ # Add deploy scripts
5
+ require 'kubec/deploy'
6
+ require 'kubec/status'
File without changes
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ module Kubec
2
+ module Utils
3
+ # :nodoc:
4
+ module Helper
5
+ class << self
6
+ def header(title, color: :green)
7
+ puts "=== #{title} ===".colorize(color)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ module Kubec
2
+ # :nodoc:
3
+ module Utils
4
+ autoload :HumanizeTime, 'kubec/utils/humanize_time'
5
+ autoload :Helper, 'kubec/utils/helper'
6
+ end
7
+ end
data/lib/kubec/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kubec
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
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
- # Your code goes here...
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.1.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-08 00:00:00.000000000 Z
12
+ date: 2018-01-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: bundler
15
+ name: colorize
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '1.16'
21
- type: :development
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: '1.16'
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: :development
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: '0.5'
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: '0.5'
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: []