picsolve_docker_builder 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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Rakefile +1 -0
  4. data/integration/compose_hello_world_new_config/.docker-builder.yml +1 -1
  5. data/integration/compose_hello_world_old_config/.docker-builder.yml +1 -1
  6. data/lib/picsolve_docker_builder/base.rb +5 -1
  7. data/lib/picsolve_docker_builder/composer/container.rb +27 -2
  8. data/lib/picsolve_docker_builder/composer/registry.rb +5 -1
  9. data/lib/picsolve_docker_builder/composer/requirements/base.rb +64 -0
  10. data/lib/picsolve_docker_builder/composer/requirements/context.rb +21 -0
  11. data/lib/picsolve_docker_builder/composer/requirements/postgres.rb +139 -0
  12. data/lib/picsolve_docker_builder/composer/requirements.rb +22 -0
  13. data/lib/picsolve_docker_builder/frame.rb +33 -4
  14. data/lib/picsolve_docker_builder/helpers/config/base.rb +1 -0
  15. data/lib/picsolve_docker_builder/helpers/config/secret.rb +1 -0
  16. data/lib/picsolve_docker_builder/helpers/config/variable_object.rb +2 -0
  17. data/lib/picsolve_docker_builder/helpers/config_manager.rb +3 -1
  18. data/lib/picsolve_docker_builder/helpers/kubeclient.rb +0 -33
  19. data/lib/picsolve_docker_builder/helpers/kubernetes/rc.rb +10 -7
  20. data/lib/picsolve_docker_builder/helpers/kubernetes/secret.rb +11 -0
  21. data/lib/picsolve_docker_builder/helpers/kubernetes_manager.rb +12 -10
  22. data/lib/picsolve_docker_builder/helpers/registry.rb +165 -0
  23. data/lib/picsolve_docker_builder/helpers/repository.rb +1 -1
  24. data/lib/picsolve_docker_builder/helpers/ssh_connection.rb +68 -0
  25. data/lib/picsolve_docker_builder/helpers/ssh_forward.rb +16 -59
  26. data/lib/picsolve_docker_builder/nodejs.rb +3 -9
  27. data/lib/picsolve_docker_builder/scala.rb +0 -5
  28. data/lib/picsolve_docker_builder/version.rb +1 -1
  29. data/picsolve_docker_builder.gemspec +2 -1
  30. metadata +25 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47c0bcbcd965d2446b0c1c9254a67bbd23a9569d
4
- data.tar.gz: 1a4f008a15c22534b990a77bca137fb4b04c0464
3
+ metadata.gz: 0d987f527c105ef90502bd0201ecb24ada6573e4
4
+ data.tar.gz: 6cacbe31a88fae3264b790e014f7c2ab40528e50
5
5
  SHA512:
6
- metadata.gz: 34289ce6a0dfea6cb6ac0b4bf23f76bad8a7300b91e3c75dbb5d63ece96f17d61e5dd9dd08d0997cf668948e98d5bf4728065c9915f8714c6ac0fe1dae473836
7
- data.tar.gz: d042eaacd90ded220dd645d5763dccc4cc0ff37e5bdd1c25f742ead7f1ed2483ab44f0d33cc6eff9ecd6d5573834979cd76554054e61452b656ca8819bf3be13
6
+ metadata.gz: 95452c0a4140df6b0e8e4d4af1f12e2ea533affad313e437c8e2768d4841d007f05ffaf20210512ba3b9f7906c4359530052d159ca36e6f3c1feba8f4a0325ec
7
+ data.tar.gz: 3ff8233cf0152f8078d398b6665caebecc5fb1029abd358f822dfe38d456c925112b559234c30982bc7d1fa3e66d443a4bed66b2d236d3480cad620b23ababd6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## [0.3.0] - 2015-11-13
4
+ ### Added
5
+
6
+ - Support creation of postgres databases if needed
7
+ - Support build without publishing docker image
8
+ - Pass environment to docker container
9
+
3
10
  ## [0.2.0] - 2015-08-26
4
11
  ### Added
5
12
  - Upgrade kubernetes api to v1
data/Rakefile CHANGED
@@ -60,6 +60,7 @@ task test_integration: [:test, :integration]
60
60
 
61
61
  desc 'Run all tests for jenkins'
62
62
  task :jenkins_prepare do
63
+ ENV['JENKINS'] = '1'
63
64
  # cleanup target
64
65
  FileUtils.rm_rf 'target'
65
66
  FileUtils.mkdir 'target'
@@ -1,7 +1,7 @@
1
1
  compose:
2
2
  app_name: hello_world_test_new
3
3
  clusters:
4
- - dev-1b.kubernetes.picsolve.net
4
+ - prod-1a.kubernetes.picsolve.net
5
5
  containers:
6
6
  helloworld:
7
7
  image: docker.picsolve.net/hello-world
@@ -1,4 +1,4 @@
1
1
  compose:
2
2
  app_name: hello_world_test
3
3
  clusters:
4
- - dev-1b.kubernetes.picsolve.net
4
+ - prod-1a.kubernetes.picsolve.net
@@ -39,8 +39,12 @@ module PicsolveDockerBuilder
39
39
  Dir.pwd
40
40
  end
41
41
 
42
+ def config_file
43
+ ENV['DOCKER_BUILDER_FILE'] || '.docker-builder.yml'
44
+ end
45
+
42
46
  def config_path
43
- File.join(base_dir, '.docker-builder.yml')
47
+ File.join(base_dir, config_file)
44
48
  end
45
49
 
46
50
  def default_config
@@ -1,5 +1,6 @@
1
1
  require 'picsolve_docker_builder/base'
2
2
  require 'picsolve_docker_builder/composer/registry'
3
+ require 'picsolve_docker_builder/composer/requirements'
3
4
 
4
5
  module PicsolveDockerBuilder
5
6
  module Composer
@@ -33,8 +34,32 @@ module PicsolveDockerBuilder
33
34
  @services[kubernetes]
34
35
  end
35
36
 
36
- def environment
37
- return nil unless config.key? 'environment'
37
+ def requirements(kubernetes)
38
+ return [] unless config.key? 'requirements'
39
+ config['requirements'].map do |name, config|
40
+ PicsolveDockerBuilder::Composer::Requirements.new(
41
+ name,
42
+ config,
43
+ PicsolveDockerBuilder::Composer::Requirements::Context.new(
44
+ kubernetes,
45
+ self
46
+ )
47
+ )
48
+ end
49
+ end
50
+
51
+ def environment(kubernetes)
52
+ env = []
53
+ log.info "evaluate dynamic stage variables #{kubernetes.stage}"
54
+ requirements(kubernetes).each do |req|
55
+ env += req.environment
56
+ end
57
+ env += environment_static
58
+ env
59
+ end
60
+
61
+ def environment_static
62
+ return [] unless config.key? 'environment'
38
63
  config['environment'].map do |key, value|
39
64
  {
40
65
  'name' => key,
@@ -42,6 +42,11 @@ module PicsolveDockerBuilder
42
42
  nil
43
43
  end
44
44
 
45
+ def self.login_basic(*args)
46
+ auth = creds(*args)
47
+ Base64.encode64("#{auth['username']}:#{auth['password']}").delete("\n")
48
+ end
49
+
45
50
  def self.repo_tag_unique(image_name)
46
51
  repo_tag = image_name.split(%r{/})[1..-1].join('/')
47
52
  repo_tag_split = repo_tag.split(/:/)
@@ -49,7 +54,6 @@ module PicsolveDockerBuilder
49
54
  tag = repo_tag_split[1] || 'latest'
50
55
 
51
56
  headers = {}
52
- login_basic = get_login_basic
53
57
  headers['Authorization'] = "Basic #{login_basic}" \
54
58
  unless login_basic.nil?
55
59
 
@@ -0,0 +1,64 @@
1
+ require 'picsolve_docker_builder/base'
2
+ require 'securerandom'
3
+ module PicsolveDockerBuilder
4
+ module Composer
5
+ module Requirements
6
+ # Base class for requirements
7
+ class Base
8
+ include PicsolveDockerBuilder::Base
9
+ attr_reader :name, :config
10
+ def initialize(name, config, context)
11
+ @name = name
12
+ @config = config
13
+ @context = context
14
+ end
15
+
16
+ def environment(_kubernetes)
17
+ []
18
+ end
19
+
20
+ def stage
21
+ @context.kubernetes.stage
22
+ end
23
+
24
+ def kubernetes
25
+ @context.kubernetes
26
+ end
27
+
28
+ def namespace
29
+ @context.namespace
30
+ end
31
+
32
+ def container
33
+ @context.container
34
+ end
35
+
36
+ def gen_password(length = 16)
37
+ SecureRandom.urlsafe_base64(length)
38
+ end
39
+
40
+ def create_secret(name, obj)
41
+ secret = Kubeclient::Secret.new
42
+ secret.metadata = {
43
+ name: name,
44
+ namespace: namespace
45
+ }
46
+ secret.data = {}
47
+ obj.each do |key, value|
48
+ secret.data[key.to_sym] = Base64.encode64(value).delete("\n")
49
+ end
50
+ kubernetes.client.create_secret secret
51
+ end
52
+
53
+ def get_secret(name)
54
+ obj = kubernetes.client.get_secret(name, namespace)
55
+ hash = {}
56
+ obj.data.to_hash.each do |key, value|
57
+ hash[key.to_s] = Base64.decode64(value)
58
+ end
59
+ hash
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,21 @@
1
+ require 'picsolve_docker_builder/base'
2
+
3
+ module PicsolveDockerBuilder
4
+ module Composer
5
+ module Requirements
6
+ # Base class for requirements
7
+ class Context
8
+ include PicsolveDockerBuilder::Base
9
+ attr_reader :kubernetes, :container
10
+ def initialize(kubernetes, container)
11
+ @kubernetes = kubernetes
12
+ @container = container
13
+ end
14
+
15
+ def namespace
16
+ @container.composer.namespace
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,139 @@
1
+ require 'base64'
2
+ require 'kubeclient'
3
+ require 'picsolve_docker_builder/composer/requirements/base'
4
+ require 'picsolve_docker_builder/helpers/ssh_connection'
5
+ require 'pg'
6
+
7
+ module PicsolveDockerBuilder
8
+ module Composer
9
+ module Requirements
10
+ # Postgres db requirements
11
+ class Postgres < Base
12
+ def ssh_forward(host, port)
13
+ @ssh = PicsolveDockerBuilder::Helpers::SshConnection.new(
14
+ ssh_host: kubernetes.host,
15
+ ssh_port: kubernetes.port
16
+ )
17
+ forward = @ssh.forward(host, port)
18
+ @ssh.start
19
+ forward
20
+ end
21
+
22
+ # get postgres secret for current container
23
+ def postgres_secret
24
+ get_secret(user_and_db_name)
25
+ rescue KubeException => e
26
+ raise e unless e.message.match(/not found/)
27
+ log.info "Secret for #{user_and_db_name} database not found"
28
+ create_postgres_secret
29
+ end
30
+
31
+ # create a new postgres secret and create the according database
32
+ def create_postgres_secret
33
+ admin_secret = admin_postgres_secret
34
+
35
+ log.info "Create secret for #{user_and_db_name} database"
36
+ container_secret = {
37
+ 'name' => user_and_db_name,
38
+ 'user' => user_and_db_name,
39
+ 'password' => gen_password,
40
+ 'host' => admin_secret['host'],
41
+ 'port' => admin_secret['port']
42
+ }
43
+ create_postgres_database(
44
+ admin_secret,
45
+ container_secret
46
+ )
47
+ create_secret(
48
+ user_and_db_name,
49
+ container_secret
50
+ )
51
+ container_secret
52
+ end
53
+
54
+ # create postgres database
55
+ # rubocop:disable Metrics/MethodLength
56
+ def create_postgres_database(admin_secret, container_secret)
57
+ log.info "Create database #{user_and_db_name}"
58
+
59
+ forward = ssh_forward(admin_secret['host'], admin_secret['port'].to_i)
60
+ admin_secret['host'] = '127.0.0.1'
61
+ admin_secret['port'] = forward.local_port
62
+
63
+ conn = PG::Connection.open(admin_secret)
64
+
65
+ user = conn.escape_string(container_secret['user'])
66
+ password = conn.escape_string(container_secret['password'])
67
+ name = conn.escape_string(container_secret['name'])
68
+
69
+ # create user
70
+ conn.exec(
71
+ "CREATE USER \"#{user}\" " \
72
+ "WITH PASSWORD '#{password}'"
73
+ )
74
+
75
+ # create db
76
+ conn.exec(
77
+ "CREATE DATABASE \"#{name}\""
78
+ )
79
+
80
+ # grant all rights to the user and the aws user
81
+ conn.exec("
82
+ GRANT ALL PRIVILEGES ON DATABASE \"#{name}\" to \"#{user}\";
83
+ GRANT ALL PRIVILEGES ON DATABASE \"#{name}\" to \"rds_superuser\";
84
+ ")
85
+
86
+ conn.close
87
+
88
+ admin_secret['dbname'] = name
89
+ admin_secret['user'] = user
90
+ admin_secret['password'] = password
91
+ conn = PG::Connection.open(admin_secret)
92
+
93
+ conn.exec("
94
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES
95
+ ON TABLES TO \"#{user}\";
96
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES
97
+ ON TABLES TO \"rds_superuser\";
98
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES
99
+ ON SEQUENCES TO \"#{user}\";
100
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES
101
+ ON SEQUENCES TO \"rds_superuser\";
102
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES
103
+ ON FUNCTIONS TO \"#{user}\";
104
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES
105
+ ON FUNCTIONS TO \"rds_superuser\";
106
+ ")
107
+ conn.close
108
+ end
109
+ # rubocop:enable Metrics/MethodLength
110
+
111
+ # get administrative postgres secrets
112
+ def admin_postgres_secret
113
+ get_secret('postgres').update('dbname' => 'postgres')
114
+ end
115
+
116
+ def user_and_db_name
117
+ "#{stage}-#{container.name}-#{name}"
118
+ end
119
+
120
+ def postgres_secret_name
121
+ "postgres-#{user_and_db_name}"
122
+ end
123
+
124
+ def environment_secret
125
+ postgres_secret.map do |key, value|
126
+ {
127
+ 'name' => "#{name.upcase}_#{key.upcase}",
128
+ 'value' => value
129
+ }
130
+ end
131
+ end
132
+
133
+ def environment
134
+ environment_secret
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,22 @@
1
+ require 'picsolve_docker_builder/composer/requirements/context'
2
+ require 'picsolve_docker_builder/composer/requirements/postgres'
3
+ module PicsolveDockerBuilder
4
+ module Composer
5
+ # Requirements are enviromental dependencies for containers
6
+ module Requirements
7
+ def self.new(name, config, context)
8
+ fail 'Requirement need to have parameter type' \
9
+ unless config.key? 'type'
10
+ object(config['type']).new(name, config, context)
11
+ end
12
+
13
+ def self.object(type)
14
+ if type == 'postgres'
15
+ Postgres
16
+ else
17
+ fail "Unknown requirement '#{type}'"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -6,6 +6,7 @@ require 'psych'
6
6
 
7
7
  module PicsolveDockerBuilder
8
8
  # Docker image building template
9
+ # rubocop:disable Metrics/ClassLength
9
10
  class Frame
10
11
  include PicsolveDockerBuilder::Base
11
12
 
@@ -138,7 +139,15 @@ module PicsolveDockerBuilder
138
139
  @docker_build = docker_build_build
139
140
  end
140
141
 
142
+ def asset_build
143
+ end
144
+
141
145
  def build
146
+ asset_build
147
+ if dest_image_name.nil?
148
+ log.info 'Skip building docker image as no dest_image is set'
149
+ return
150
+ end
142
151
  docker_build
143
152
  end
144
153
 
@@ -229,13 +238,33 @@ module PicsolveDockerBuilder
229
238
  @container ||= create_container
230
239
  end
231
240
 
241
+ def environment
242
+ blacklist = %w(
243
+ SSH_CLIENT
244
+ SSH_CONNECTION
245
+ LD_LIBRARY_PATH
246
+ PATH
247
+ NVM_DIR
248
+ NVM_NODEJS_ORG_MIRROR)
249
+
250
+ keys = ENV.keys
251
+ keys = keys.reject do |key|
252
+ blacklist.include? key
253
+ end
254
+
255
+ keys.map do |key|
256
+ "#{key}=#{ENV[key]}"
257
+ end
258
+ end
259
+
232
260
  def create_container
233
261
  command = ['/bin/sleep', '3600']
234
262
  c = Docker::Container.create(
235
- 'Image' => asset_image.id,
236
- 'Cmd' => command,
237
- 'OpenStdin' => false,
238
- 'WorkingDir' => '/_build'
263
+ 'Image' => asset_image.id,
264
+ 'Cmd' => command,
265
+ 'OpenStdin' => false,
266
+ 'WorkingDir' => '/_build',
267
+ 'Env' => environment
239
268
  )
240
269
  at_exit do
241
270
  stop
@@ -6,6 +6,7 @@ module PicsolveDockerBuilder
6
6
  def self.name
7
7
  nil
8
8
  end
9
+
9
10
  def initialize(_identifier)
10
11
  end
11
12
  end
@@ -6,6 +6,7 @@ module PicsolveDockerBuilder
6
6
  def self.name
7
7
  'secret'
8
8
  end
9
+
9
10
  def initialize(_identifier)
10
11
  end
11
12
  end
@@ -7,9 +7,11 @@ module PicsolveDockerBuilder
7
7
  def self.regex_full
8
8
  /^\$\{([^\}]*)\}$/
9
9
  end
10
+
10
11
  def self.regex
11
12
  /\$\{[^\}]*\}/
12
13
  end
14
+
13
15
  # Checks if a string needs to be replaced by an VariableObject
14
16
  def self.replace_string(obj)
15
17
  return obj unless VariableObject.regex.match(obj)
@@ -28,7 +28,9 @@ module PicsolveDockerBuilder
28
28
  end
29
29
 
30
30
  def eval_container_config(config)
31
- config['environment'] = eval_container_env(config['environment'])
31
+ # eval environment if key exits
32
+ config['environment'] = eval_container_env(config['environment']) \
33
+ if config.key? 'environment'
32
34
  config
33
35
  end
34
36
 
@@ -1,34 +1 @@
1
1
  require 'kubeclient'
2
-
3
- module Kubeclient
4
- module Common
5
- # Hot fix for kubeclient should be going upstream
6
- # * https://github.com/abonas/kubeclient/pull/96
7
- class Client
8
- def get_entities(entity_type, klass, options)
9
- params = {}
10
- if options[:label_selector]
11
- params['params'] = { labelSelector: options[:label_selector] }
12
- end
13
-
14
- ns_prefix = build_namespace_prefix(options[:namespace])
15
- response = handle_exception do
16
- rest_client[ns_prefix + resource_name(entity_type)]
17
- .get(params.merge(@headers))
18
- end
19
-
20
- result = JSON.parse(response)
21
-
22
- resource_version = result.fetch('resourceVersion', nil)
23
- if resource_version.nil?
24
- resource_version =
25
- result.fetch('metadata', {}).fetch('resourceVersion', nil)
26
- end
27
-
28
- collection = result['items'].map { |item| new_entity(item, klass) }
29
-
30
- EntityList.new(entity_type, resource_version, collection)
31
- end
32
- end
33
- end
34
- end
@@ -12,10 +12,9 @@ module PicsolveDockerBuilder
12
12
  end
13
13
 
14
14
  def existing_rcs
15
- rcs = client.get_replication_controllers(
16
- namespace: @image.composer.namespace
17
- ).select do |rc|
18
- rc.metadata.name.match(/^#{@image.name}/)
15
+ rcs = client.get_replication_controllers.select do |rc|
16
+ rc.metadata.name.match(/^#{@image.name}/) && \
17
+ rc.metadata.namespace == @image.composer.namespace
19
18
  end
20
19
  rcs.map do |rc|
21
20
  Rc.new(@image, @kubernetes, rc)
@@ -49,7 +48,7 @@ module PicsolveDockerBuilder
49
48
  }
50
49
  # append environment variables if in place
51
50
  if @image.class.instance_methods.include? :environment
52
- env = @image.environment
51
+ env = @image.environment(@kubernetes)
53
52
  c['env'] = env unless env.nil?
54
53
  end
55
54
  [c]
@@ -76,10 +75,14 @@ module PicsolveDockerBuilder
76
75
  end
77
76
 
78
77
  def pods_by_selector(selector)
79
- client.get_pods(
78
+ pods = client.get_pods(
80
79
  namespace: @rc.metadata.namespace,
81
80
  label_selector: selector
82
- ).map do |pod|
81
+ ).select do |pod|
82
+ pod.metadata.namespace == @rc.metadata.namespace
83
+ end
84
+
85
+ pods.map do |pod|
83
86
  Pod.new(pod, @kubernetes)
84
87
  end
85
88
  end
@@ -0,0 +1,11 @@
1
+ require 'picsolve_docker_builder/helpers/kubernetes/resource'
2
+
3
+ module PicsolveDockerBuilder
4
+ module Helpers
5
+ module Kubernetes
6
+ # A kubernetes secret
7
+ class Secret < Resource
8
+ end
9
+ end
10
+ end
11
+ end
@@ -2,7 +2,7 @@ require 'picsolve_docker_builder/helpers/kubeclient'
2
2
  require 'picsolve_docker_builder/helpers/kubernetes/rc'
3
3
  require 'picsolve_docker_builder/helpers/kubernetes/service'
4
4
  require 'picsolve_docker_builder/helpers/kubernetes/pod'
5
- require 'picsolve_docker_builder/helpers/ssh_forward'
5
+ require 'picsolve_docker_builder/helpers/ssh_connection'
6
6
  require 'picsolve_docker_builder/base'
7
7
 
8
8
  module PicsolveDockerBuilder
@@ -31,6 +31,10 @@ module PicsolveDockerBuilder
31
31
  @composer = composer
32
32
  end
33
33
 
34
+ def user
35
+ 'core'
36
+ end
37
+
34
38
  def create_client
35
39
  Kubeclient::Client.new kubernetes_url, 'v1'
36
40
  end
@@ -48,8 +52,8 @@ module PicsolveDockerBuilder
48
52
  end
49
53
 
50
54
  def kubernetes_url_ssh_forward_stop
51
- @ssh_forward.stop unless @ssh_forward.nil?
52
- @ssh_forward = nil
55
+ @ssh.stop unless @ssh_forward.nil?
56
+ @ssh = nil
53
57
  end
54
58
 
55
59
  def stop
@@ -57,18 +61,16 @@ module PicsolveDockerBuilder
57
61
  end
58
62
 
59
63
  def kubernetes_url_ssh_forward
60
- @ssh_forward = SshForward.new(
64
+ @ssh = SshConnection.new(
61
65
  ssh_host: host,
62
- ssh_port: port,
63
- local_port: 10_000,
64
- remote_host: '127.0.0.1',
65
- remote_port: 8080
66
+ ssh_port: port
66
67
  )
67
- port = @ssh_forward.start
68
+ forward = @ssh.forward('127.0.0.1', 8080, 10_000)
69
+ @ssh.start
68
70
  at_exit do
69
71
  kubernetes_url_ssh_forward_stop
70
72
  end
71
- "http://127.0.0.1:#{port}"
73
+ "http://127.0.0.1:#{forward.local_port}"
72
74
  end
73
75
 
74
76
  def client
@@ -0,0 +1,165 @@
1
+ require 'picsolve_docker_builder/base'
2
+ require 'excon'
3
+ require 'json'
4
+ require 'base64'
5
+
6
+ module PicsolveDockerBuilder
7
+ module Helpers
8
+ # This represents a remote registry, that is queried for
9
+ # for informations about images
10
+ class Registry
11
+ include PicsolveDockerBuilder::Base
12
+
13
+ attr_reader :config
14
+
15
+ def initialize(registry)
16
+ @registry = registry
17
+ end
18
+
19
+ def api_version_unsupported
20
+ fail 'No supported version found at registry'
21
+ end
22
+
23
+ def api_version
24
+ return @api_version unless @api_version.nil?
25
+ if connection.get(path: '/v2/').status == 200
26
+ @api_version = :v2
27
+ elsif connection.get(path: '/v1/_ping').status == 200
28
+ @api_version = :v1
29
+ else
30
+ api_version_unsupported
31
+ end
32
+ log.info "Detected api version #{@api_version} on registry #{@registry}"
33
+ @api_version
34
+ end
35
+
36
+ def list_tags_v1(image)
37
+ endpoint = "/v1/repositories/#{image}/tags"
38
+ r = connection.get(path: endpoint)
39
+ JSON.parse(r.body)
40
+ end
41
+
42
+ def list_tags_v2(image)
43
+ endpoint = "/v2/#{image}/tags/list"
44
+ r = connection.get(path: endpoint)
45
+ o = {}
46
+ JSON.parse(r.body)['tags'].each do |tag|
47
+ endpoint = "/v2/#{image}/manifests/#{tag}"
48
+ r = connection.get(path: endpoint)
49
+ digest = Digest::SHA2.new(256)
50
+ JSON.parse(r.body)['fsLayers'].each do |fs_hash|
51
+ digest.update(fs_hash['blobSum'])
52
+ end
53
+ o[tag] = digest.to_s
54
+ end
55
+ o
56
+ end
57
+
58
+ def unique_tag(image, tag)
59
+ tags = list_tags(image)
60
+ fail "tag '#{tag}' not found" unless tags.include? tag
61
+ tags.each do |my_tag, hash|
62
+ # next if not right name
63
+ next unless my_tag.match(/^jenkins-/)
64
+ # next hash not matching
65
+ next if hash != tags[tag]
66
+ # return tag name now
67
+ return my_tag
68
+ end
69
+ fail "no unique tag found for tag=#{tag}"
70
+ end
71
+
72
+ def list_tags(image)
73
+ if api_version == :v1
74
+ list_tags_v1(image)
75
+ elsif api_version == :v2
76
+ list_tags_v2(image)
77
+ else
78
+ api_version_unsupported
79
+ end
80
+ end
81
+
82
+ def http_host
83
+ URI(@registry).host
84
+ end
85
+
86
+ def headers
87
+ {
88
+ 'Host' => http_host
89
+ }
90
+ end
91
+
92
+ def connection
93
+ @connection ||= Excon.new(
94
+ @registry,
95
+ headers: headers
96
+ )
97
+ end
98
+
99
+ def self.dockercfg_path
100
+ File.expand_path '~/.dockercfg'
101
+ end
102
+
103
+ def self.dockercfg
104
+ JSON.parse(
105
+ File.open(
106
+ dockercfg_path
107
+ ).read
108
+ )
109
+ end
110
+
111
+ def self.creds(*args)
112
+ auth = Base64.decode64(
113
+ get_login_basic(
114
+ *args
115
+ )
116
+ ).split(':')
117
+ {
118
+ 'username' => auth[0],
119
+ 'password' => auth[1]
120
+ }
121
+ end
122
+
123
+ def self.get_login_basic(registry = 'docker.picsolve.net')
124
+ dockercfg[registry]['auth']
125
+ rescue StandardError
126
+ nil
127
+ end
128
+
129
+ def self.repo_tag_unique(image_name)
130
+ repo_tag = image_name.split(%r{/})[1..-1].join('/')
131
+ repo_tag_split = repo_tag.split(/:/)
132
+ repo = repo_tag_split[0]
133
+ tag = repo_tag_split[1] || 'latest'
134
+
135
+ headers = {}
136
+ login_basic = get_login_basic
137
+ headers['Authorization'] = "Basic #{login_basic}" \
138
+ unless login_basic.nil?
139
+
140
+ connection = Excon.new(
141
+ 'https://docker.picsolve.net',
142
+ headers: headers,
143
+ persistent: true
144
+ )
145
+ response = connection.get(path: "/v1/repositories/#{repo}/tags")
146
+
147
+ tags = JSON.parse(response.body)
148
+
149
+ hash = tags[tag]
150
+
151
+ tags.each do |t, h|
152
+ next if h != hash
153
+ next if t == tag
154
+ next unless t.match(/jenkins-[0-9]+/)
155
+ return {
156
+ tag_unique: "#{image_name.split(':').first}:#{t}",
157
+ hash: hash
158
+ }
159
+ end
160
+
161
+ fail "Can not find a uniqe tag for #{image_name}"
162
+ end
163
+ end
164
+ end
165
+ end
@@ -19,7 +19,7 @@ module PicsolveDockerBuilder
19
19
  split_length_1(split)
20
20
  elsif split.length == 2
21
21
  split_length_2(split)
22
- elsif split.length == 3
22
+ elsif split.length == 3
23
23
  split_length_3(split)
24
24
  end
25
25
  end
@@ -0,0 +1,68 @@
1
+ require 'picsolve_docker_builder/helpers/ssh_forward'
2
+ require 'picsolve_docker_builder/base'
3
+ require 'net/ssh'
4
+
5
+ module PicsolveDockerBuilder
6
+ module Helpers
7
+ # Ruby class that can forward a remote port over SSH
8
+ class SshConnection
9
+ include PicsolveDockerBuilder::Base
10
+ attr_reader :options
11
+ def initialize(opts)
12
+ @options = opts
13
+ end
14
+
15
+ def connection
16
+ @connection ||= Net::SSH.start(
17
+ ssh_host,
18
+ ssh_user,
19
+ port: ssh_port
20
+ )
21
+ end
22
+
23
+ def forward(*args)
24
+ SshForward.forward(connection, *args)
25
+ end
26
+
27
+ def start
28
+ log.debug "Connecting via ssh to host '#{ssh_user}@#{ssh_host}'"
29
+ # start thread with ssh
30
+ @thread = Thread.new do
31
+ connection.loop { true }
32
+ end
33
+ end
34
+
35
+ def stop
36
+ return if @thread.nil?
37
+ @thread.kill
38
+ @thread.join
39
+ log.debug \
40
+ "Disconnected ssh connection to host '#{ssh_user}@#{ssh_host}'"
41
+ end
42
+
43
+ def ssh_user
44
+ options[:ssh_user] = 'core'
45
+ end
46
+
47
+ def ssh_host
48
+ options[:ssh_host]
49
+ end
50
+
51
+ def ssh_port
52
+ options[:ssh_port] || 22
53
+ end
54
+
55
+ def remote_host
56
+ options[:remote_host]
57
+ end
58
+
59
+ def remote_port
60
+ options[:remote_port]
61
+ end
62
+
63
+ def local_port
64
+ options[:local_port] || remote_port
65
+ end
66
+ end
67
+ end
68
+ end
@@ -5,79 +5,36 @@ module PicsolveDockerBuilder
5
5
  module Helpers
6
6
  # Ruby class that can forward a remote port over SSH
7
7
  class SshForward
8
- include PicsolveDockerBuilder::Base
9
- attr_reader :options
10
- def initialize(opts)
11
- @options = opts
8
+ def self.forward(*args)
9
+ f = new(*args)
10
+ f.bind_port
11
+ f
12
12
  end
13
13
 
14
- def connection
15
- @connection ||= Net::SSH.start(
16
- ssh_host,
17
- ssh_user,
18
- port: ssh_port
19
- )
14
+ include PicsolveDockerBuilder::Base
15
+ attr_reader :connection, :local_port
16
+ def initialize(connection, remote_host, remote_port, local_port = nil)
17
+ @connection = connection
18
+ @remote_host = remote_host
19
+ @remote_port = remote_port
20
+ @local_port = local_port || remote_port
20
21
  end
21
22
 
22
23
  def bind_port
23
24
  tries = 0
24
- port = local_port
25
25
  begin
26
- connection.forward.local(port, remote_host, remote_port)
27
- return port
26
+ connection.forward.local(@local_port, @remote_host, @remote_port)
27
+ log.info "forward remote port #{@remote_host}:#{@remote_port}" \
28
+ " to local port #{@local_port}"
29
+ return @local_port
28
30
  rescue Errno::EADDRINUSE => e
29
31
  # raise after five failed tries
30
32
  raise e if tries > 5
31
33
  tries += 1
32
- port += 1
34
+ @local_port += 1
33
35
  retry
34
36
  end
35
37
  end
36
-
37
- def start
38
- log.debug "Connecting via ssh to host '#{ssh_user}@#{ssh_host}'"
39
-
40
- # bind remote service to local port
41
- port = bind_port
42
-
43
- # start thread with ssh
44
- @thread = Thread.new do
45
- connection.loop { true }
46
- end
47
- port
48
- end
49
-
50
- def stop
51
- return if @thread.nil?
52
- @thread.kill
53
- @thread.join
54
- log.debug \
55
- "Disconnected ssh connection to host '#{ssh_user}@#{ssh_host}'"
56
- end
57
-
58
- def ssh_user
59
- options[:ssh_user] = 'core'
60
- end
61
-
62
- def ssh_host
63
- options[:ssh_host]
64
- end
65
-
66
- def ssh_port
67
- options[:ssh_port] || 22
68
- end
69
-
70
- def remote_host
71
- options[:remote_host]
72
- end
73
-
74
- def remote_port
75
- options[:remote_port]
76
- end
77
-
78
- def local_port
79
- options[:local_port] || remote_port
80
- end
81
38
  end
82
39
  end
83
40
  end
@@ -16,8 +16,7 @@ module PicsolveDockerBuilder
16
16
  c['nodejs'] = {
17
17
  'build_commands' => [
18
18
  'npm install',
19
- 'grunt',
20
- 'tar cvzf html.tar.gz -C frontend/dist .'
19
+ 'grunt jenkins'
21
20
  ]
22
21
  }
23
22
  c
@@ -35,8 +34,8 @@ module PicsolveDockerBuilder
35
34
  def docker_build_files
36
35
  f = []
37
36
  f << Builder::File.new(
38
- 'app.tar.gz',
39
- source: File.join(base_dir, 'html.tar.gz'),
37
+ 'dist.tar.gz',
38
+ source: File.join(base_dir, 'dist.tar.gz'),
40
39
  destination: '/var/www/html'
41
40
  )
42
41
 
@@ -126,10 +125,5 @@ module PicsolveDockerBuilder
126
125
 
127
126
  stop
128
127
  end
129
-
130
- def build
131
- asset_build
132
- docker_build
133
- end
134
128
  end
135
129
  end
@@ -187,10 +187,5 @@ module PicsolveDockerBuilder
187
187
  if tgz_files.length > 1
188
188
  tgz_files[0]
189
189
  end
190
-
191
- def build
192
- asset_build
193
- docker_build
194
- end
195
190
  end
196
191
  end
@@ -1,4 +1,4 @@
1
1
  # version
2
2
  module PicsolveDockerBuilder
3
- VERSION = '0.2.0'
3
+ VERSION = '0.3.0'
4
4
  end
@@ -29,7 +29,8 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency 'simplecov'
30
30
  spec.add_development_dependency 'simplecov-cobertura'
31
31
  spec.add_dependency 'rake', '~> 10.0'
32
- spec.add_dependency 'kubeclient', '~> 0.3.0'
32
+ spec.add_dependency 'kubeclient', '~> 0.5.1'
33
33
  spec.add_dependency 'docker-api'
34
34
  spec.add_dependency 'net-ssh'
35
+ spec.add_dependency 'pg'
35
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: picsolve_docker_builder
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
  - Christian Simon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-26 00:00:00.000000000 Z
11
+ date: 2015-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 0.3.0
131
+ version: 0.5.1
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 0.3.0
138
+ version: 0.5.1
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: docker-api
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: pg
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  description:
168
182
  email:
169
183
  - christian.simon@picsolve.com
@@ -232,6 +246,10 @@ files:
232
246
  - lib/picsolve_docker_builder/composer/container.rb
233
247
  - lib/picsolve_docker_builder/composer/image.rb
234
248
  - lib/picsolve_docker_builder/composer/registry.rb
249
+ - lib/picsolve_docker_builder/composer/requirements.rb
250
+ - lib/picsolve_docker_builder/composer/requirements/base.rb
251
+ - lib/picsolve_docker_builder/composer/requirements/context.rb
252
+ - lib/picsolve_docker_builder/composer/requirements/postgres.rb
235
253
  - lib/picsolve_docker_builder/frame.rb
236
254
  - lib/picsolve_docker_builder/helpers/config/base.rb
237
255
  - lib/picsolve_docker_builder/helpers/config/secret.rb
@@ -241,9 +259,12 @@ files:
241
259
  - lib/picsolve_docker_builder/helpers/kubernetes/pod.rb
242
260
  - lib/picsolve_docker_builder/helpers/kubernetes/rc.rb
243
261
  - lib/picsolve_docker_builder/helpers/kubernetes/resource.rb
262
+ - lib/picsolve_docker_builder/helpers/kubernetes/secret.rb
244
263
  - lib/picsolve_docker_builder/helpers/kubernetes/service.rb
245
264
  - lib/picsolve_docker_builder/helpers/kubernetes_manager.rb
265
+ - lib/picsolve_docker_builder/helpers/registry.rb
246
266
  - lib/picsolve_docker_builder/helpers/repository.rb
267
+ - lib/picsolve_docker_builder/helpers/ssh_connection.rb
247
268
  - lib/picsolve_docker_builder/helpers/ssh_forward.rb
248
269
  - lib/picsolve_docker_builder/nodejs.rb
249
270
  - lib/picsolve_docker_builder/scala.rb