kozo 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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -2
  3. data/.kzignore +1 -0
  4. data/.overcommit.yml +1 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +44 -5
  7. data/CHANGELOG.md +5 -0
  8. data/Gemfile +3 -1
  9. data/Gemfile.lock +156 -48
  10. data/LICENSE.md +1 -1
  11. data/README.md +28 -0
  12. data/Rakefile +3 -7
  13. data/bin/kozo +6 -2
  14. data/config/application.rb +3 -0
  15. data/config/dependencies.rb +4 -25
  16. data/kozo.gemspec +20 -5
  17. data/lib/core_ext/boolean.rb +12 -0
  18. data/lib/core_ext/nil_class.rb +11 -0
  19. data/lib/core_ext/string.rb +25 -0
  20. data/lib/kozo/backend.rb +81 -0
  21. data/lib/kozo/backends/git.rb +50 -0
  22. data/lib/kozo/backends/local.rb +41 -15
  23. data/lib/kozo/backends/memory.rb +26 -0
  24. data/lib/kozo/cli.rb +30 -9
  25. data/lib/kozo/command.rb +32 -0
  26. data/lib/kozo/commands/apply.rb +44 -0
  27. data/lib/kozo/commands/console.rb +15 -0
  28. data/lib/kozo/commands/import.rb +47 -0
  29. data/lib/kozo/commands/init.rb +15 -0
  30. data/lib/kozo/commands/plan.rb +29 -3
  31. data/lib/kozo/commands/refresh.rb +21 -0
  32. data/lib/kozo/commands/show.rb +15 -0
  33. data/lib/kozo/commands/state.rb +64 -0
  34. data/lib/kozo/commands/validate.rb +13 -0
  35. data/lib/kozo/commands/version.rb +13 -0
  36. data/lib/kozo/concerns/assignment.rb +17 -0
  37. data/lib/kozo/concerns/attributes.rb +99 -0
  38. data/lib/kozo/concerns/mark.rb +25 -0
  39. data/lib/kozo/concerns/track.rb +47 -0
  40. data/lib/kozo/configuration.rb +34 -7
  41. data/lib/kozo/dsl.rb +18 -12
  42. data/lib/kozo/error.rb +13 -0
  43. data/lib/kozo/logger.rb +8 -4
  44. data/lib/kozo/operation.rb +42 -0
  45. data/lib/kozo/operations/create.rb +29 -0
  46. data/lib/kozo/operations/destroy.rb +29 -0
  47. data/lib/kozo/operations/show.rb +12 -0
  48. data/lib/kozo/operations/update.rb +19 -0
  49. data/lib/kozo/options.rb +9 -1
  50. data/lib/kozo/parser.rb +35 -0
  51. data/lib/kozo/provider.rb +7 -1
  52. data/lib/kozo/providers/dummy/dependencies.rb +9 -0
  53. data/lib/kozo/providers/{null → dummy}/provider.rb +2 -6
  54. data/lib/kozo/providers/dummy/resource.rb +19 -0
  55. data/lib/kozo/providers/dummy/resources/dummy.rb +16 -0
  56. data/lib/kozo/providers/hcloud/dependencies.rb +13 -0
  57. data/lib/kozo/providers/hcloud/provider.rb +7 -1
  58. data/lib/kozo/providers/hcloud/resource.rb +46 -1
  59. data/lib/kozo/providers/hcloud/resources/server.rb +29 -0
  60. data/lib/kozo/providers/hcloud/resources/ssh_key.rb +6 -2
  61. data/lib/kozo/resource.rb +110 -3
  62. data/lib/kozo/state.rb +25 -0
  63. data/lib/kozo/type.rb +15 -0
  64. data/lib/kozo/types/boolean.rb +30 -0
  65. data/lib/kozo/types/date.rb +20 -0
  66. data/lib/kozo/types/float.rb +17 -0
  67. data/lib/kozo/types/hash.rb +20 -0
  68. data/lib/kozo/types/integer.rb +17 -0
  69. data/lib/kozo/types/string.rb +17 -0
  70. data/lib/kozo/types/time.rb +18 -0
  71. data/lib/kozo/version.rb +1 -1
  72. data/lib/kozo.rb +13 -7
  73. metadata +195 -31
  74. data/.github/dependabot.yml +0 -14
  75. data/.github/workflows/ci.yml +0 -81
  76. data/bin/bundle +0 -118
  77. data/bin/console +0 -7
  78. data/bin/rspec +0 -28
  79. data/bin/version +0 -62
  80. data/lib/kozo/backends/base.rb +0 -31
  81. data/lib/kozo/commands/base.rb +0 -21
  82. data/lib/kozo/container.rb +0 -35
  83. data/lib/kozo/environment.rb +0 -27
  84. data/lib/kozo/providers/null/resource.rb +0 -11
  85. data/lib/kozo/providers/null/resources/null.rb +0 -13
  86. data/log/.keep +0 -0
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Providers
5
+ module HCloud
6
+ module Resources
7
+ class Server < Resource
8
+ self.resource_name = "hcloud_server"
9
+
10
+ attribute :name
11
+ attribute :image
12
+ attribute :server_type
13
+ attribute :location
14
+ attribute :datacenter
15
+
16
+ attribute :user_data
17
+
18
+ attribute :labels, type: :hash
19
+
20
+ attribute :ssh_keys, multiple: true
21
+
22
+ attribute :locked, argument: false, type: :boolean
23
+
24
+ attribute :created, argument: false, type: :time
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -5,9 +5,13 @@ module Kozo
5
5
  module HCloud
6
6
  module Resources
7
7
  class SSHKey < Resource
8
- attr_accessor :name, :public_key
8
+ self.resource_name = "hcloud_ssh_key"
9
9
 
10
- self.name = "hcloud_ssh_key"
10
+ attribute :name
11
+ attribute :public_key
12
+ attribute :labels, type: :hash
13
+
14
+ attribute :created, type: :time, argument: false
11
15
  end
12
16
  end
13
17
  end
data/lib/kozo/resource.rb CHANGED
@@ -2,12 +2,119 @@
2
2
 
3
3
  module Kozo
4
4
  class Resource
5
- attr_accessor :id, :provider
5
+ include Attributes
6
6
 
7
- class_attribute :name, :provider
7
+ include Assignment
8
+ include Mark
9
+ include Track
10
+
11
+ attr_accessor :provider, :state_name
12
+
13
+ attribute :id
14
+
15
+ class_attribute :resource_name, :provider_name
16
+
17
+ def address
18
+ "#{resource_name}.#{state_name}"
19
+ end
8
20
 
9
21
  def ==(other)
10
- id == other.id
22
+ self.class == other.class &&
23
+ id == other.id &&
24
+ state_name == other.state_name
25
+ end
26
+
27
+ alias eql? ==
28
+
29
+ def hash
30
+ [self.class, id].hash
31
+ end
32
+
33
+ def to_h
34
+ {
35
+ meta: meta,
36
+ data: attributes,
37
+ }
38
+ end
39
+
40
+ def self.from_h(hash)
41
+ Kozo
42
+ .container
43
+ .resolve("resource.#{hash.dig(:meta, :resource)}")
44
+ .tap { |r| hash[:data].each { |k, v| r.send(:"#{k}=", v) } }
45
+ .tap { |r| r.state_name = hash.dig(:meta, :name) }
46
+ end
47
+
48
+ ##
49
+ # Refetch resource from remote infrastructure
50
+ #
51
+ def refresh!
52
+ Kozo.logger.info "#{address}: refreshing state"
53
+
54
+ refresh
55
+
56
+ Kozo.logger.info "#{address}: refreshed state"
57
+ end
58
+
59
+ ##
60
+ # Create resource in remote infrastructure
61
+ #
62
+ def create!
63
+ Kozo.logger.info "#{address}: creating resource"
64
+
65
+ create
66
+
67
+ Kozo.logger.info "#{address}: created resource"
68
+ end
69
+
70
+ ##
71
+ # Update resource in remote infrastructure
72
+ #
73
+ def update!
74
+ Kozo.logger.info "#{address}: updating resource"
75
+
76
+ update
77
+
78
+ Kozo.logger.info "#{address}: updated resource"
79
+ end
80
+
81
+ ##
82
+ # Destroy resource in remote infrastructure
83
+ #
84
+ def destroy!
85
+ Kozo.logger.info "#{address}: destroying resource"
86
+
87
+ destroy
88
+
89
+ Kozo.logger.info "#{address}: destroyed resource"
90
+ end
91
+
92
+ protected
93
+
94
+ def refresh
95
+ raise NotImplementedError
96
+ end
97
+
98
+ def create
99
+ raise NotImplementedError
100
+ end
101
+
102
+ def update
103
+ raise NotImplementedError
104
+ end
105
+
106
+ def destroy
107
+ raise NotImplementedError
108
+ end
109
+
110
+ private
111
+
112
+ def meta
113
+ {
114
+ name: state_name,
115
+ provider: provider_name,
116
+ resource: resource_name,
117
+ }
11
118
  end
12
119
  end
13
120
  end
data/lib/kozo/state.rb ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ class State
5
+ VERSION = 1
6
+
7
+ attr_accessor :resources
8
+
9
+ def initialize(resources = nil)
10
+ @resources = Set.new(resources)
11
+ end
12
+
13
+ def ==(other)
14
+ resources == other.resources
15
+ end
16
+
17
+ def to_h
18
+ {
19
+ version: VERSION,
20
+ kozo_version: Kozo::VERSION,
21
+ resources: resources.map(&:to_h),
22
+ }
23
+ end
24
+ end
25
+ end
data/lib/kozo/type.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ class Type
5
+ def self.lookup(type)
6
+ "Kozo::Types::#{type.to_s.camelize}".constantize
7
+ rescue NameError
8
+ raise ArgumentError, "No such type: #{type}"
9
+ end
10
+
11
+ def self.cast(value); end
12
+
13
+ def self.serialize(value); end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Types
5
+ class Boolean < Type
6
+ # rubocop:disable Lint/BooleanSymbol
7
+ FALSE_VALUES = [
8
+ false, 0,
9
+ "0", :"0",
10
+ "f", :f,
11
+ "F", :F,
12
+ "false", :false,
13
+ "FALSE", :FALSE,
14
+ "off", :off,
15
+ "OFF", :OFF,
16
+ ].freeze
17
+ # rubocop:enable Lint/BooleanSymbol
18
+
19
+ def self.cast(value)
20
+ return if value.nil?
21
+
22
+ !FALSE_VALUES.include?(value)
23
+ end
24
+
25
+ def self.serialize(value)
26
+ value
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Types
5
+ class Date < Type
6
+ def self.cast(value)
7
+ return unless value
8
+ return value if value.is_a?(::Date)
9
+
10
+ ::Date.parse(value)
11
+ rescue ::Date::Error => e
12
+ raise ArgumentError, e
13
+ end
14
+
15
+ def self.serialize(value)
16
+ value&.iso8601
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Types
5
+ class Float < Type
6
+ def self.cast(value)
7
+ return unless value
8
+
9
+ send :Float, value
10
+ end
11
+
12
+ def self.serialize(value)
13
+ value
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Types
5
+ class Hash < Type
6
+ def self.cast(value)
7
+ return unless value
8
+ return value if value.is_a?(::Hash)
9
+
10
+ value.to_h
11
+ rescue TypeError, NoMethodError => e
12
+ raise ArgumentError, e
13
+ end
14
+
15
+ def self.serialize(value)
16
+ value
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Types
5
+ class Integer < Type
6
+ def self.cast(value)
7
+ return unless value
8
+
9
+ send :Integer, value
10
+ end
11
+
12
+ def self.serialize(value)
13
+ value
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Types
5
+ class String < Type
6
+ def self.cast(value)
7
+ return unless value
8
+
9
+ send :String, value
10
+ end
11
+
12
+ def self.serialize(value)
13
+ value
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Types
5
+ class Time < Type
6
+ def self.cast(value)
7
+ return unless value
8
+ return value if value.is_a?(::Time)
9
+
10
+ ::Time.parse(value)
11
+ end
12
+
13
+ def self.serialize(value)
14
+ value&.iso8601
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/kozo/version.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Kozo
4
4
  module Version
5
5
  MAJOR = 0
6
- MINOR = 1
6
+ MINOR = 2
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
data/lib/kozo.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "zeitwerk"
4
3
  require "active_support/all"
4
+ require "active_model"
5
+ require "colorize"
6
+ require "dinja"
7
+ require "zeitwerk"
8
+
9
+ require "byebug" if ENV["ENV"] == "development"
5
10
 
6
11
  module Kozo
7
12
  class << self
@@ -16,11 +21,7 @@ module Kozo
16
21
  end
17
22
 
18
23
  def container
19
- @container ||= Container.new
20
- end
21
-
22
- def env
23
- @env ||= Environment.new
24
+ @container ||= Dinja::Container.new
24
25
  end
25
26
 
26
27
  def logger
@@ -30,13 +31,18 @@ module Kozo
30
31
  def setup
31
32
  @loader = Zeitwerk::Loader.for_gem
32
33
 
34
+ # Register inflections
33
35
  instance_eval(File.read(root.join("config/inflections.rb")))
34
36
 
37
+ # Set up code loader
35
38
  loader.enable_reloading
39
+ loader.ignore(root.join("lib/**/*/dependencies.rb"))
40
+ loader.collapse(root.join("lib/kozo/concerns"))
36
41
  loader.setup
37
42
  loader.eager_load
38
43
 
39
- container.instance_eval(File.read(root.join("config/dependencies.rb")))
44
+ # Register dependencies
45
+ Dir[root.join("lib/**/*/dependencies.rb"), root.join("config/dependencies.rb")].each { |d| container.instance_eval(File.read(d)) }
40
46
  end
41
47
  end
42
48
  end