kuby-core 0.1.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 (67) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +21 -0
  5. data/README.md +186 -0
  6. data/Rakefile +14 -0
  7. data/kuby-core.gemspec +27 -0
  8. data/lib/kuby.rb +112 -0
  9. data/lib/kuby/basic_logger.rb +22 -0
  10. data/lib/kuby/cli_base.rb +75 -0
  11. data/lib/kuby/definition.rb +29 -0
  12. data/lib/kuby/docker.rb +27 -0
  13. data/lib/kuby/docker/alpine.rb +62 -0
  14. data/lib/kuby/docker/assets_phase.rb +11 -0
  15. data/lib/kuby/docker/bundler_phase.rb +56 -0
  16. data/lib/kuby/docker/cli.rb +72 -0
  17. data/lib/kuby/docker/copy_phase.rb +23 -0
  18. data/lib/kuby/docker/credentials.rb +11 -0
  19. data/lib/kuby/docker/debian.rb +66 -0
  20. data/lib/kuby/docker/dockerfile.rb +128 -0
  21. data/lib/kuby/docker/errors.rb +22 -0
  22. data/lib/kuby/docker/layer_stack.rb +42 -0
  23. data/lib/kuby/docker/local_tags.rb +38 -0
  24. data/lib/kuby/docker/metadata.rb +69 -0
  25. data/lib/kuby/docker/package_list.rb +34 -0
  26. data/lib/kuby/docker/package_phase.rb +59 -0
  27. data/lib/kuby/docker/packages.rb +10 -0
  28. data/lib/kuby/docker/packages/managed_package.rb +29 -0
  29. data/lib/kuby/docker/packages/nodejs.rb +29 -0
  30. data/lib/kuby/docker/packages/package.rb +22 -0
  31. data/lib/kuby/docker/packages/yarn.rb +47 -0
  32. data/lib/kuby/docker/phase.rb +21 -0
  33. data/lib/kuby/docker/remote_tags.rb +24 -0
  34. data/lib/kuby/docker/setup_phase.rb +29 -0
  35. data/lib/kuby/docker/spec.rb +147 -0
  36. data/lib/kuby/docker/tags.rb +39 -0
  37. data/lib/kuby/docker/timestamp_tag.rb +36 -0
  38. data/lib/kuby/docker/webserver_phase.rb +51 -0
  39. data/lib/kuby/docker/yarn_phase.rb +11 -0
  40. data/lib/kuby/kubernetes.rb +16 -0
  41. data/lib/kuby/kubernetes/deployer.rb +94 -0
  42. data/lib/kuby/kubernetes/docker_config.rb +27 -0
  43. data/lib/kuby/kubernetes/errors.rb +22 -0
  44. data/lib/kuby/kubernetes/manifest.rb +56 -0
  45. data/lib/kuby/kubernetes/minikube_provider.rb +51 -0
  46. data/lib/kuby/kubernetes/plugin.rb +55 -0
  47. data/lib/kuby/kubernetes/plugins.rb +8 -0
  48. data/lib/kuby/kubernetes/plugins/nginx_ingress.rb +61 -0
  49. data/lib/kuby/kubernetes/plugins/rails_app.rb +16 -0
  50. data/lib/kuby/kubernetes/plugins/rails_app/database.rb +58 -0
  51. data/lib/kuby/kubernetes/plugins/rails_app/mysql.rb +142 -0
  52. data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +393 -0
  53. data/lib/kuby/kubernetes/plugins/rails_app/postgres.rb +10 -0
  54. data/lib/kuby/kubernetes/plugins/rails_app/rewrite_db_config.rb +13 -0
  55. data/lib/kuby/kubernetes/plugins/rails_app/sqlite.rb +10 -0
  56. data/lib/kuby/kubernetes/plugins/rails_app/tasks.rake +23 -0
  57. data/lib/kuby/kubernetes/provider.rb +77 -0
  58. data/lib/kuby/kubernetes/registry_secret.rb +26 -0
  59. data/lib/kuby/kubernetes/spec.rb +152 -0
  60. data/lib/kuby/middleware.rb +5 -0
  61. data/lib/kuby/middleware/health_check.rb +16 -0
  62. data/lib/kuby/railtie.rb +18 -0
  63. data/lib/kuby/tasks.rb +135 -0
  64. data/lib/kuby/tasks/kuby.rake +63 -0
  65. data/lib/kuby/trailing_hash.rb +19 -0
  66. data/lib/kuby/version.rb +3 -0
  67. metadata +233 -0
@@ -0,0 +1,22 @@
1
+ module Kuby
2
+ module Docker
3
+ class BuildError < StandardError; end
4
+ class PushError < StandardError; end
5
+
6
+ class MissingTagError < StandardError
7
+ attr_reader :tag
8
+
9
+ def initialize(tag)
10
+ @tag = tag
11
+ end
12
+
13
+ def message
14
+ @message ||= "Could not find tag '#{tag}'."
15
+ end
16
+ end
17
+
18
+ class UnsupportedDistroError < StandardError; end
19
+ class MissingPackageError < StandardError; end
20
+ class MissingDistroError < StandardError; end
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ module Kuby
2
+ module Docker
3
+ class LayerStack
4
+ include Enumerable
5
+
6
+ attr_reader :stack, :layers
7
+
8
+ def initialize
9
+ @stack = []
10
+ @layers = {}
11
+ end
12
+
13
+ def each
14
+ return to_enum(__method__) unless block_given?
15
+ @stack.each { |name| yield layers[name] }
16
+ end
17
+
18
+ def use(name, layer)
19
+ stack << name
20
+ layers[name] = layer
21
+ end
22
+
23
+ def insert(name, layer, options = {})
24
+ existing_name = options[:before] || options[:after]
25
+ idx = stack.index(existing_name)
26
+
27
+ unless idx
28
+ raise ArgumentError, "Could not find existing layer '#{existing_name}'"
29
+ end
30
+
31
+ idx += 1 if options[:after]
32
+ stack.insert(idx, name)
33
+ layers[name] = layer
34
+ end
35
+
36
+ def delete(name)
37
+ stack.delete(name)
38
+ layers.delete(name)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ module Kuby
2
+ module Docker
3
+ class LocalTags
4
+ attr_reader :cli, :metadata
5
+
6
+ def initialize(cli, metadata)
7
+ @cli = cli
8
+ @metadata = metadata
9
+ end
10
+
11
+ def tags
12
+ images = cli.images(metadata.image_url)
13
+ images.map { |image| image[:tag] }
14
+ end
15
+
16
+ def latest_tags
17
+ # find "latest" tag
18
+ images = cli.images(metadata.image_url)
19
+ latest = images.find { |image| image[:tag] == Tags::LATEST }
20
+
21
+ unless latest
22
+ raise MissingTagError.new(Tags::LATEST)
23
+ end
24
+
25
+ # find all tags that point to the same image as 'latest'
26
+ images.each_with_object([]) do |image_data, tags|
27
+ if image_data[:id] == latest[:id]
28
+ tags << image_data[:tag]
29
+ end
30
+ end
31
+ end
32
+
33
+ def timestamp_tags
34
+ tags.map { |t| TimestampTag.try_parse(t) }.compact
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,69 @@
1
+ require 'uri'
2
+
3
+ module Kuby
4
+ module Docker
5
+ class Metadata
6
+ DEFAULT_DISTRO = :debian
7
+ DEFAULT_REGISTRY_HOST = 'https://docker.io'.freeze
8
+ LATEST_TAG = 'latest'
9
+
10
+ attr_accessor :image_url
11
+ attr_reader :definition, :distro
12
+
13
+ def initialize(definition)
14
+ @definition = definition
15
+ @tags = []
16
+ end
17
+
18
+ def image_url
19
+ @image_url || default_image_url
20
+ end
21
+
22
+ def image_host
23
+ @image_host ||= if image_url.include?('/')
24
+ uri = parse_url(image_url)
25
+ "#{uri.scheme}://#{uri.host}"
26
+ else
27
+ DEFAULT_REGISTRY_HOST
28
+ end
29
+ end
30
+
31
+ def image_repo
32
+ @image_repo ||= if image_url.include?('/')
33
+ parse_url(image_url).path.sub(/\A\//, '')
34
+ else
35
+ image_url
36
+ end
37
+ end
38
+
39
+ def tags
40
+ @tags.empty? ? default_tags : @tags
41
+ end
42
+
43
+ def distro=(distro_name)
44
+ @distro = distro_name
45
+ end
46
+
47
+ private
48
+
49
+ def default_image_url
50
+ # assuming dockerhub by not specifying full url
51
+ @default_image_url ||= definition.app_name.downcase
52
+ end
53
+
54
+ def default_tags
55
+ @default_tags ||= [
56
+ TimestampTag.new(Time.now).to_s, LATEST_TAG
57
+ ]
58
+ end
59
+
60
+ def parse_url(url)
61
+ uri = URI.parse(url)
62
+ return uri if uri.scheme
63
+
64
+ # force a scheme because URI.parse won't work properly without one
65
+ URI.parse("https://#{url}")
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,34 @@
1
+ module Kuby
2
+ module Docker
3
+ class PackageList
4
+ include Enumerable
5
+
6
+ attr_reader :packages
7
+
8
+ def initialize(package_tuples)
9
+ @packages = []
10
+ package_tuples.each { |pt| add(*pt) }
11
+ end
12
+
13
+ def [](name)
14
+ packages.find { |pkg| pkg.name == name }
15
+ end
16
+
17
+ def add(name, version = nil)
18
+ packages << Package.new(name, version)
19
+ end
20
+
21
+ def delete(name)
22
+ packages.delete_if { |pkg| pkg.name == name }
23
+ end
24
+
25
+ def each(&block)
26
+ packages.each(&block)
27
+ end
28
+
29
+ def empty?
30
+ packages.empty?
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,59 @@
1
+ module Kuby
2
+ module Docker
3
+ class PackagePhase < Phase
4
+ attr_reader :operations
5
+
6
+ def initialize(*args)
7
+ super
8
+
9
+ @operations = []
10
+ end
11
+
12
+ def add(package_name, version = nil)
13
+ operations << [:add, package_name, version]
14
+ end
15
+
16
+ def remove(package_name)
17
+ operations << [:remove, package_name]
18
+ end
19
+
20
+ def apply_to(dockerfile)
21
+ packages = distro_spec.default_packages.dup
22
+
23
+ operations.each do |operator, package_name, version|
24
+ if operator == :add
25
+ packages << [package_name, version]
26
+ else
27
+ packages.reject! do |pkg_name_to_del, *|
28
+ pkg_name_to_del == package_name
29
+ end
30
+ end
31
+ end
32
+
33
+ packages.map! do |package_name, version|
34
+ get_package(package_name, version)
35
+ end
36
+
37
+ distro_spec.install(packages, into: dockerfile)
38
+ end
39
+
40
+ private
41
+
42
+ def distro_spec
43
+ definition.docker.distro_spec
44
+ end
45
+
46
+ def get_package(package_name, version)
47
+ if package = Kuby.packages[package_name]
48
+ package.with_version(version)
49
+ else
50
+ raise MissingPackageError, "package '#{package_name}' hasn't been registered"
51
+ end
52
+ end
53
+
54
+ def metadata
55
+ definition.docker.metadata
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,10 @@
1
+ module Kuby
2
+ module Docker
3
+ module Packages
4
+ autoload :ManagedPackage, 'kuby/docker/packages/managed_package'
5
+ autoload :Nodejs, 'kuby/docker/packages/nodejs'
6
+ autoload :Package, 'kuby/docker/packages/package'
7
+ autoload :Yarn, 'kuby/docker/packages/yarn'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ module Kuby
2
+ module Docker
3
+ module Packages
4
+ class ManagedPackage
5
+ attr_reader :name, :names_per_distro
6
+
7
+ def initialize(name, names_per_distro)
8
+ @name = name
9
+ @names_per_distro = names_per_distro
10
+ end
11
+
12
+ def package_name_for(distro)
13
+ names_per_distro.fetch(distro) do
14
+ raise UnsupportedDistroError, "Couldn't install #{name} "\
15
+ "because #{distro} is an unsupported distro"
16
+ end
17
+ end
18
+
19
+ def with_version(*)
20
+ self
21
+ end
22
+
23
+ def managed?
24
+ true
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module Kuby
2
+ module Docker
3
+ module Packages
4
+ class Nodejs < Package
5
+ def install_on_debian(dockerfile)
6
+ install_from_image("node:#{version}", dockerfile)
7
+ end
8
+
9
+ def install_on_alpine(dockerfile)
10
+ install_from_image("node:#{version}-alpine", dockerfile)
11
+ end
12
+
13
+ def version
14
+ @version || 'current'
15
+ end
16
+
17
+ private
18
+
19
+ def install_from_image(image, dockerfile)
20
+ dockerfile.insert_at(0) do
21
+ dockerfile.from(image, as: 'nodejs')
22
+ end
23
+
24
+ dockerfile.copy('/usr/local/bin/node', '/usr/local/bin/node', from: 'nodejs')
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ module Kuby
2
+ module Docker
3
+ module Packages
4
+ class Package
5
+ attr_reader :name, :version
6
+
7
+ def initialize(name, version = nil)
8
+ @name = name
9
+ @version = version
10
+ end
11
+
12
+ def with_version(ver)
13
+ self.class.new(name, ver)
14
+ end
15
+
16
+ def managed?
17
+ false
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ module Kuby
2
+ module Docker
3
+ module Packages
4
+ class Yarn < Package
5
+ def install_on_debian(dockerfile)
6
+ dockerfile.run(<<~CMD.strip)
7
+ wget #{url} && \\
8
+ yarnv=$(basename $(ls yarn-*.tar.gz | cut -d'-' -f 2) .tar.gz) && \\
9
+ tar zxvf yarn-$yarnv.tar.gz -C /opt && \\
10
+ mv /opt/yarn-$yarnv /opt/yarn && \\
11
+ apt-get install -qq -y --no-install-recommends gnupg && \\
12
+ wget -qO- https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --import && \\
13
+ wget https://github.com/yarnpkg/yarn/releases/download/$yarnv/yarn-$yarnv.tar.gz.asc && \\
14
+ gpg --verify yarn-$yarnv.tar.gz.asc
15
+ CMD
16
+
17
+ dockerfile.env("PATH=$PATH:/opt/yarn/bin")
18
+ end
19
+
20
+ def install_on_alpine(dockerfile)
21
+ dockerfile.run(<<~CMD.strip)
22
+ wget #{url} && \\
23
+ yarnv=$(basename $(ls yarn-*.tar.gz | cut -d'-' -f 2) .tar.gz) && \\
24
+ tar zxvf yarn-$yarnv.tar.gz -C /opt && \\
25
+ mv /opt/yarn-$yarnv /opt/yarn && \\
26
+ apk add --no-cache gnupg && \\
27
+ wget -qO- https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --import && \\
28
+ wget https://github.com/yarnpkg/yarn/releases/download/$yarnv/yarn-$yarnv.tar.gz.asc && \\
29
+ gpg --verify yarn-$yarnv.tar.gz.asc
30
+ CMD
31
+
32
+ dockerfile.env("PATH=$PATH:/opt/yarn/bin")
33
+ end
34
+
35
+ private
36
+
37
+ def url
38
+ @url ||= if version
39
+ "https://github.com/yarnpkg/yarn/releases/download/v#{version}/yarn-v#{version}.tar.gz"
40
+ else
41
+ "https://yarnpkg.com/latest.tar.gz"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ module Kuby
2
+ module Docker
3
+ class Phase
4
+ attr_reader :definition
5
+
6
+ def initialize(definition)
7
+ @definition = definition
8
+ end
9
+
10
+ private
11
+
12
+ def app
13
+ definition.app
14
+ end
15
+
16
+ def metadata
17
+ definition.docker.metadata
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module Kuby
2
+ module Docker
3
+ class RemoteTags
4
+ attr_reader :remote_client, :metadata
5
+
6
+ def initialize(remote_client, metadata)
7
+ @remote_client = remote_client
8
+ @metadata = metadata
9
+ end
10
+
11
+ def tags
12
+ remote_client.tags
13
+ end
14
+
15
+ def latest_tags
16
+ raise NotImplementedError, 'latest tags are not available for remote repos'
17
+ end
18
+
19
+ def timestamp_tags
20
+ tags.map { |t| TimestampTag.try_parse(t) }.compact
21
+ end
22
+ end
23
+ end
24
+ end