k8sflow 0.10.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 212a6cc23a37f94da1a18f90469d06b974501ac1
4
+ data.tar.gz: 11dd94712047a9649259c1cd00e504fc07984d75
5
+ SHA512:
6
+ metadata.gz: 0f79e9da6c2ddea9e9430fa2d28f1ebf5a0b969001529c1a4b326a55c48a96152e9da70a21e87fad1fa8e806fe5ab82bfaa5091311bb9d90e60eedac6b8ade7f
7
+ data.tar.gz: a238b77ff59ac2777b5ca992c1d48b546cf30d8bb2a1d189e6da74829a9347d07d02230274615a115de61339512c354e7099896c6ff28ba31dc0d52a00e8f9d8
data/Changelog ADDED
@@ -0,0 +1,3 @@
1
+ - 0.0.1
2
+ * Initial version
3
+ -- Antoine Legrand <antoine.legrand@ubudu.com> 27/07/2013
data/License ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Antoine Legrand (ant.legrand@gmail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ K8sflow
2
+ ==========
data/bin/k8sflow ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'k8sflow'
3
+
4
+ K8sflow::Cli.run(ARGV)
@@ -0,0 +1,10 @@
1
+
2
+ require 'clitopic/cli'
3
+ require 'k8sflow/command'
4
+ module K8sflow
5
+ class Cli
6
+ def self.run(args)
7
+ Clitopic::Cli.run(args)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,165 @@
1
+ require 'erb'
2
+ module K8sflow
3
+
4
+ module Image
5
+ class ImageBase < Clitopic::Command::Base
6
+ class << self
7
+
8
+ def kv_parse(list)
9
+ vars = {}
10
+ list.each do |e|
11
+ sp = e.split("=")
12
+ key = sp[0..-2].join("=")
13
+ value = sp[-1]
14
+ vars[key] = value
15
+ end
16
+ return vars
17
+ end
18
+
19
+ def vars
20
+ if @vars.nil?
21
+ @vars = {}
22
+ if !options[:build_vars].nil?
23
+ if options[:build_vars].is_a?(Hash)
24
+ @vars = options[:build_vars]
25
+ else
26
+ @vars = kv_parse(options[:build_vars])
27
+ end
28
+ end
29
+ if !options[:vars].nil?
30
+ if options[:vars].is_a?(Hash)
31
+ @vars.merge!(options[:vars])
32
+ else
33
+ @vars.merge!(kv_parse(options[:vars]))
34
+ end
35
+ end
36
+ end
37
+
38
+ @vars["tag"] = @options[:tag]
39
+ return @vars
40
+ end
41
+
42
+ def files
43
+ f = []
44
+ options[:files].each do |file|
45
+ if !file.start_with?("/")
46
+ file = "#{@options[:path]}/#{file}"
47
+ end
48
+ file_list = Dir.glob(file)
49
+ f << file_list
50
+ end
51
+ return f
52
+ end
53
+
54
+ def tag
55
+ @options[:tag]
56
+ end
57
+
58
+
59
+ def create_dockerfile
60
+ tag = @options[:tag]
61
+ dir = "#{@options[:path]}/#{@options[:tag]}"
62
+ puts "- Remove previous dir: #{dir}"
63
+ FileUtils.rm_rf dir
64
+ puts "- Create dir: #{dir}"
65
+ FileUtils.mkdir_p dir
66
+ files.each do |file_list|
67
+ puts "- Copy files: #{file_list}"
68
+ FileUtils.cp(file_list, dir)
69
+ end
70
+ puts "- Read Dockerfile template: #{@options[:path]}/#{@options[:tpl]}"
71
+ tpl = "#{@options[:path]}/#{@options[:tpl]}"
72
+ File.open(tpl, 'rb') do |file|
73
+ tpl = file.read
74
+ end
75
+ b = binding
76
+ puts "- Write Dockerfile: #{dir}/Dockerfile"
77
+ puts " with vars:\n#{vars.map{|k,v| " #{k}: #{v}"}.join("\n")}"
78
+ File.open("#{dir}/Dockerfile", 'wb') do |file|
79
+ file.write(ERB.new(tpl).result b)
80
+ end
81
+
82
+ puts "-----------------------------------------------"
83
+ end
84
+
85
+ def dockerbuild
86
+ dir = "#{@options[:path]}/#{@options[:tag]}"
87
+ cmd = "docker -H #{@options[:docker_api]} build #{@options[:build_opts]} -t #{@options[:registry]}:#{tag} #{dir} "
88
+ puts cmd
89
+ system(cmd)
90
+ end
91
+
92
+ def dockerpush
93
+ cmd = "docker -H #{@options[:docker_api]} push #{@options[:registry]}:#{tag}"
94
+ puts cmd
95
+ system(cmd)
96
+ end
97
+
98
+ end
99
+ end
100
+
101
+
102
+ class ImageTopic < Clitopic::Topic::Base
103
+ register name: 'image',
104
+ description: 'Mange image lifecylces'
105
+
106
+ option :registry, '-r', '--registry DOCKER_REPO', 'Docker registry to pull/fetch images'
107
+ option :path, '-p', '--path DOCKERFILE PATH', 'dockerfiles source directory to'
108
+ option :build_vars, "--build-vars key=value,key=value" , Array, "Default variables"
109
+ option :docker_api, "-H", "--host", "docker api endpoint", default: "tcp://localhost:4243"
110
+ option :tag, '-t', '--tag TAG', "Image tag", default: 'latest'
111
+ end
112
+
113
+
114
+ class Dockerfile < ImageBase
115
+ register name: 'dockerfile',
116
+ banner: 'image:dockerfile [options]',
117
+ description: 'Generate a dockerfile with templated vars .',
118
+ topic: 'image'
119
+
120
+ option :files, "-f", "--files FILE1,FILE2", Array, "List files to copy in dockerfile directory, i.e 'files/*',/etc/conf.cfg'"
121
+ option :tpl, "-l", "--tpl=Dockerfile", "The Dockerfile Template", default: 'Dockerfile.tpl'
122
+ option :vars, "-x", "--vars=VARS", Array, "Variables required by the dockerfile"
123
+ option :tag, '-t', '--tag TAG', "Image tag", default: 'master'
124
+
125
+ def self.call
126
+ create_dockerfile
127
+ end
128
+ end
129
+
130
+ class Build < ImageBase
131
+ register name: 'build',
132
+ description: 'build docker image',
133
+ banner: 'image:build [OPTIONS]',
134
+ topic: 'image'
135
+
136
+ option :build, "--build OPTS", "docker build options"
137
+ def self.call
138
+ dockerbuild
139
+ end
140
+ end
141
+
142
+ class Push < ImageBase
143
+ register name: 'push',
144
+ description: 'push dockerimage to docker hub',
145
+ banner: 'image:push [OPTIONS]',
146
+ topic: 'image'
147
+
148
+ option :build, "--build=[OPTS]", "docker build options"
149
+ def self.call
150
+ dockerbuild if @options[:build] != nil
151
+ dockerpush
152
+ end
153
+ end
154
+
155
+ class List < Clitopic::Command::Base
156
+ register name: 'list',
157
+ description: 'List available tags in a registry',
158
+ topic: 'image'
159
+
160
+ def self.call
161
+ end
162
+ end
163
+ end
164
+
165
+ end
@@ -0,0 +1,38 @@
1
+ module K8sflow
2
+ module Maintenance
3
+ class MaintenanceTopic < Clitopic::Topic::Base
4
+ register name: 'maintenance',
5
+ description: 'Switch application in maintenance mode'
6
+
7
+ option :app, '-A', '--app app-backend', 'Application backend set in HAPROXY'
8
+ option :api, '--api API_ENDPOINT', 'Endpoint to configure haproxy'
9
+ end
10
+
11
+ class Status < Clitopic::Command::Base
12
+ register name: 'status',
13
+ description: 'View maintenance status',
14
+ topic: 'maintenance'
15
+
16
+ def self.call
17
+ end
18
+ end
19
+
20
+ class On < Clitopic::Command::Base
21
+ register name: 'on',
22
+ description: 'Enable maintenance mode',
23
+ topic: 'maintenance'
24
+
25
+ def self.call
26
+ end
27
+ end
28
+
29
+ class Off < Clitopic::Command::Base
30
+ register name: 'off',
31
+ description: 'disable maintenance mode',
32
+ topic: 'maintenance'
33
+
34
+ def self.call
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,114 @@
1
+ require 'optparse'
2
+ require 'optparse/time'
3
+ require 'docker'
4
+ require 'k8sflow/utils/heroku'
5
+ module K8sflow
6
+ module Command
7
+
8
+ class Run < Clitopic::Command::Base
9
+ register name: 'index',
10
+ banner: 'Usage: k8sflow run [options] CMD',
11
+ description: "Run CMD on a (de)attached container
12
+
13
+ Exemples:
14
+ Run a rails console
15
+ $ k8sflow run -t 2.27.3 -r mydocker/repo -e APP_ENV=production -h tcp://docker-host:4243 rails console
16
+
17
+ Run a web server detached and bind container port to host port
18
+ $ k8sflow run -t 2.10 -p 3000:3000 'run server -p 3000'
19
+ ",
20
+ topic: {name: 'run', description: 'Run CMD on a (de)attached container'}
21
+
22
+ option :port, "-p", "--port ctn_port:host_port", Array, "Publish a container's port(s) to the host"
23
+ option :port_all, "-P", "--port-all", Array, "Publish all exposed ports to random ports"
24
+ option :detach, "-d", "--detach", "daemonize container", default: false
25
+ option :tag, "-t", "--tag TAG", "image-tag"
26
+ option :registry, "-r", "--registry REPO", "image-repository"
27
+ option :app, "-A", "--app APPNAME", "application name"
28
+ option :envs, "-e", "--env VAR=VALUE,VAR2=VALUE2", Array, "envvars list"
29
+ option :heroku, "--heroku APP", "get all envs from heroku"
30
+ option :heroku_db, "--heroku-db", "get DB envs only from heroku"
31
+ option :tty, "--[no-]tty", "Use tty"
32
+ option :docker_api, "-h", "--host", "docker api endpoint", default: "tcp://localhost:4243"
33
+ option :aliases, "--aliases a=x,b=y", "commands aliases, usefull in the default file"
34
+
35
+ class << self
36
+ attr_accessor :aliases
37
+
38
+ def aliases
39
+ @aliases ||= {}
40
+ end
41
+
42
+ def get_cmd(args)
43
+ if args.size == 0
44
+ raise ArgumentError.new('no CMD')
45
+ else
46
+ cmd = args.join(" ").strip
47
+ puts cmd
48
+ if !@options[:aliases].nil? && @options[:aliases].is_a?(Hash)
49
+ @aliases.merge!(@options[:aliases])
50
+ end
51
+ cmd = aliases[cmd] if aliases.has_key?(cmd)
52
+ return cmd
53
+ end
54
+ end
55
+
56
+ def env_vars(options)
57
+ envs = {}
58
+ if options.has_key?(:envs)
59
+ options[:envs].each do |e|
60
+ sp = e.split("=")
61
+ key = sp[0..-2].join("=")
62
+ value = sp[-1]
63
+ envs[key] = value
64
+ end
65
+ end
66
+ if options.has_key?(:heroku)
67
+ envs.merge!( K8sflow::Utils::HerokuClient.envs(options[:heroku], options[:heroku_db]))
68
+ end
69
+ pp envs
70
+ return envs
71
+ end
72
+
73
+ def docker_run(cmd, envs, options)
74
+ Docker.url = options[:docker_api]
75
+ container_info = {
76
+ 'Cmd' => cmd.split(" "),
77
+ 'Image' => "#{options[:registry]}:#{options[:tag]}",
78
+ 'Env' => envs.map{|k| "#{k[0]}=#{k[1]}"},
79
+ 'OpenStdin' => true
80
+ }
81
+ if !options[:detach]
82
+ container_info["Tty"] = true
83
+ end
84
+ if options[:port]
85
+ ctn_port, host_port = options[:port].split(":")
86
+ container_info["HostConfig"] = {
87
+ "PortBindings": { "#{ctn_port}/tcp": [{ "HostPort": host_port.to_s}] }
88
+ }
89
+ end
90
+ if options[:port_all] == true
91
+ container_info["PublishAllPorts"] = true
92
+ end
93
+ pp container_info
94
+ container = Docker::Container.create(container_info)
95
+ container.start
96
+ puts "container created with id: #{container.id}"
97
+ if !options[:detach]
98
+ puts "docker -H #{Docker.url} attach #{container.id}"
99
+ exec("docker -H #{Docker.url} attach #{container.id}")
100
+ end
101
+ end
102
+
103
+ def call
104
+ pp options
105
+ cmd = get_cmd(arguments)
106
+ envs = env_vars(options)
107
+ docker_run(cmd, envs, options)
108
+ end
109
+ end
110
+
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,3 @@
1
+ Dir[File.join(File.dirname(__FILE__), "command", "*.rb")].each do |file|
2
+ require file
3
+ end
@@ -0,0 +1,57 @@
1
+ require 'pp'
2
+ require 'heroku-api'
3
+ require 'netrc'
4
+ require 'json'
5
+
6
+ module K8sflow
7
+ module Utils
8
+ class HerokuClient
9
+ HEROKU_API_HOST = "api.heroku.com"
10
+ attr_accessor :heroku, :api_token
11
+ class << self
12
+ def client
13
+ if @client.nil?
14
+ user, token = netrc[HEROKU_API_HOST]
15
+ @client = Heroku::API.new(:api_key => token)
16
+ end
17
+ return @client
18
+ end
19
+
20
+ def netrc # :nodoc:
21
+ @netrc ||= begin
22
+ File.exists?(netrc_path) ? Netrc.read(netrc_path) : raise(StandardError)
23
+ rescue => error
24
+ puts netrc_path
25
+ raise ".netrc missing or no entry found. Try `heroku auth:login`"
26
+ end
27
+ end
28
+
29
+ def netrc_path # :nodoc:
30
+ default = Netrc.default_path
31
+ encrypted = default + ".gpg"
32
+ if File.exists?(encrypted)
33
+ encrypted
34
+ else
35
+ default
36
+ end
37
+ end
38
+
39
+ def envs(app, db_only=true)
40
+ envs = client.get_config_vars(app).body
41
+ # pp "overrided vars: #{@options.envvars}"
42
+ db_vars = ["DATABASE_URL",
43
+ "MEMCACHIER_PASSWORD",
44
+ "MEMCACHIER_SERVERS",
45
+ "MEMCACHIER_USERNAME",
46
+ "REDISTOGO_URL",
47
+ "REDIS_PROVIDER"]
48
+ if db_only == true
49
+ envs.select!{|k,v| db_vars.index(k) != nil}
50
+ end
51
+ pp envs
52
+ return envs
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module K8sflow
2
+ VERSION = '0.10.0'
3
+ end
data/lib/k8sflow.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'clitopic'
2
+ require 'k8sflow/version'
3
+
4
+ Clitopic.version = K8sflow::VERSION
5
+ #Clitopic.parser = Clitopic::Parser::OptParser
6
+ Clitopic.commands_dir = "#{__FILE__}/k8sflow/command"
7
+ Clitopic.default_files = [File.join(Dir.getwd, ".k8sflow.yml"), File.join(Dir.home, ".k8sflow.yml")]
8
+
9
+
10
+ require 'k8sflow/cli'
11
+
12
+
13
+ K8sflow::Command::Run.aliases = {'c' => 'rails console', 's' => 'rails server', 'console' => "rails console", "server" => "rails server"}
@@ -0,0 +1,6 @@
1
+ require 'kubeflow'
2
+ describe Kubeflow::VERSION do
3
+ it "should be equal 0.0.1" do
4
+ expect(Kubeflow::VERSION).to eql("0.0.1")
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ require 'kubeflow'
2
+ describe MultiCli::Topic do
3
+ it "Add topic in class variable" do
4
+ a = MultiCli::Topic.new(name: 'topic1', description: "description1", hidden: true)
5
+ expect(MultiCli::Topic.topics[
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: k8sflow
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.0
5
+ platform: ruby
6
+ authors:
7
+ - Antoine Legrand
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cli-topic
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ description: Manage workflow from source to kubernetes deployement
28
+ email:
29
+ - ant.legrand@gmail.com
30
+ executables:
31
+ - k8sflow
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - Changelog
36
+ - License
37
+ - README.md
38
+ - bin/k8sflow
39
+ - lib/k8sflow.rb
40
+ - lib/k8sflow/cli.rb
41
+ - lib/k8sflow/command.rb
42
+ - lib/k8sflow/command/image.rb
43
+ - lib/k8sflow/command/maintenance.rb
44
+ - lib/k8sflow/command/run.rb
45
+ - lib/k8sflow/utils/heroku.rb
46
+ - lib/k8sflow/version.rb
47
+ - spec/kubeflow_spec.rb
48
+ - spec/topic_spec.rb
49
+ homepage: http://gitlab.com/ant31
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.0
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.4.5
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: Manage workflow from source to docker to kubernetes deployement
73
+ test_files:
74
+ - spec/kubeflow_spec.rb
75
+ - spec/topic_spec.rb
76
+ has_rdoc: