chapp 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 231652d4a0cae298d0e709fbb14f61bccd2adc9d
4
+ data.tar.gz: c6d90b4a20d780bb50e601a98a5227f71b224fc2
5
+ SHA512:
6
+ metadata.gz: e0348558a2205618b5403a867b825358b06911819903ee13f2aed7048a301b576a02cbdd0a309148b69fe17852a723e6b4e2cefaa1d87282a7b26ec7c75bbef1
7
+ data.tar.gz: 9ee83c73e05352bd6102400204a7205eaa5ce734c54cb5ca6e01758f02fd8783ca40c70c87a04f85b8b591694cc4fc48f5044da1f558ffdc49c5b85f673cf20e
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # coding: UTF-8
2
+
3
+ source 'https://rubygems.org/'
4
+
5
+ gemspec
@@ -0,0 +1,12 @@
1
+ require 'chapp/app'
2
+ require 'chapp/app_instance'
3
+ require 'chapp/wiring'
4
+ require 'chapp/database'
5
+
6
+ module Chapp
7
+
8
+ def self.database
9
+ Chapp::Database.new
10
+ end
11
+
12
+ end
@@ -0,0 +1,191 @@
1
+ require 'chapp'
2
+ require 'chef/node/attribute'
3
+
4
+ module Chapp
5
+ class App
6
+
7
+ # TODO: Define allowed characters (.)
8
+
9
+ DEFAULT_RECIPE = "default"
10
+
11
+ attr_reader :used_apps
12
+ attr_reader :dependencies
13
+
14
+ def self.from_file app_file
15
+ appString = IO.read app_file
16
+
17
+ app = App.new
18
+ app.instance_eval appString
19
+
20
+ app
21
+ end
22
+
23
+ def self.from_hash app_hash
24
+ app = App.new
25
+
26
+ app.group app_hash["group"]
27
+ app.name app_hash["name"]
28
+
29
+ app.pre_run_list app_hash["pre_run_list"]
30
+ app.post_run_list app_hash["post_run_list"]
31
+
32
+ app.run_list app_hash["run_list"]
33
+
34
+ app_hash["dependencies"].each do |cookbook, version_constraint|
35
+ app.depends cookbook, version_constraint
36
+ end
37
+
38
+ app_hash["used_apps"].each do |app_name|
39
+ app.uses app_name
40
+ end
41
+
42
+ app.node Chef::Node::Attribute.new({}, app_hash["node"], {}, {}).default
43
+ app.environment app_hash["environment"]
44
+
45
+ if app_hash.include? "type"
46
+ app.type app_hash["type"]
47
+ end
48
+
49
+ if app_hash.include? "recipe"
50
+ app.recipe app_hash["recipe"]
51
+ end
52
+
53
+ if app_hash.include? "cookbook"
54
+ app.cookbook app_hash["cookbook"]
55
+ end
56
+
57
+ app
58
+ end
59
+
60
+ def initialize
61
+ @group = nil
62
+ @name = nil
63
+ @used_apps = Array.new
64
+ @dependencies = Hash.new
65
+ @pre_run_list = Array.new
66
+ @post_run_list = Array.new
67
+ @environment = nil
68
+ @node = Chef::Node::Attribute.new({}, {}, {}, {}).default
69
+ @run_list = nil
70
+ @type = nil
71
+ @recipe = nil
72
+ @cookbook = nil
73
+ end
74
+
75
+ def group group=nil
76
+ set_or_return :group, group
77
+ end
78
+
79
+ def name name=nil
80
+ set_or_return :name, name
81
+ end
82
+
83
+ def id
84
+ "#{group}_#{name}"
85
+ end
86
+
87
+ def uses app=nil
88
+ @used_apps.push app
89
+ end
90
+
91
+ def cookbook cookbook=nil
92
+ set_or_return_with_default :cookbook, @name, cookbook
93
+ end
94
+
95
+ def recipe recipe=nil
96
+ set_or_return_with_default :recipe, DEFAULT_RECIPE, recipe
97
+ end
98
+
99
+ def type type=nil
100
+ set_or_return_with_default :type, cookbook, type
101
+ end
102
+
103
+ def depends cookbook, version_constraint
104
+ @dependencies.store cookbook, version_constraint
105
+ end
106
+
107
+ def pre_run_list *recipes
108
+ if recipes.length > 0
109
+ @pre_run_list = recipes
110
+ else
111
+ @pre_run_list
112
+ end
113
+ end
114
+
115
+ def post_run_list *recipes
116
+ if recipes.length > 0
117
+ @post_run_list = recipes
118
+ else
119
+ @post_run_list
120
+ end
121
+ end
122
+
123
+ def node node=nil
124
+ set_or_return :node, node
125
+ end
126
+
127
+ def run_list run_list=nil
128
+ set_or_return :run_list, run_list
129
+ end
130
+
131
+ def environment environment=nil
132
+ set_or_return :environment, environment
133
+ end
134
+
135
+ def to_hash
136
+ hash = Hash.new
137
+
138
+ hash.store "group", group
139
+ hash.store "name", name
140
+ hash.store "used_apps", used_apps
141
+
142
+ hash.store "pre_run_list", pre_run_list
143
+ hash.store "post_run_list", post_run_list
144
+
145
+ hash.store "dependencies", dependencies
146
+
147
+ hash.store "node", node.to_hash
148
+ hash.store "environment", environment
149
+
150
+ if @type
151
+ hash.store "type", type
152
+ end
153
+
154
+ if @recipe
155
+ hash.store "recipe", recipe
156
+ end
157
+
158
+ if @cookbook
159
+ hash.store "cookbook", cookbook
160
+ end
161
+
162
+ hash
163
+ end
164
+
165
+ private
166
+
167
+ def set_or_return(symbol, arg)
168
+ iv_symbol = "@#{symbol.to_s}".to_sym
169
+ if arg == nil
170
+ self.instance_variable_get(iv_symbol)
171
+ else
172
+ self.instance_variable_set(iv_symbol, arg)
173
+ end
174
+ end
175
+
176
+ def set_or_return_with_default(symbol, default_val, arg)
177
+ iv_symbol = "@#{symbol.to_s}".to_sym
178
+ if arg == nil
179
+ val = self.instance_variable_get(iv_symbol)
180
+ if val
181
+ val
182
+ else
183
+ default_val
184
+ end
185
+ else
186
+ self.instance_variable_set(iv_symbol, arg)
187
+ end
188
+ end
189
+
190
+ end
191
+ end
@@ -0,0 +1,17 @@
1
+ require 'chapp'
2
+
3
+ module Chapp
4
+ class AppInstance
5
+
6
+ attr_reader :app_name
7
+ attr_reader :node_name
8
+ attr_reader :fqdn
9
+
10
+ def initialize app_name, node_name, fqdn
11
+ @app_name = app_name
12
+ @node_name = node_name
13
+ @fqdn = fqdn
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,187 @@
1
+ require 'chapp'
2
+ require 'chef/role'
3
+ require 'chef/environment'
4
+ require 'chef/data_bag'
5
+ require 'chef/data_bag_item'
6
+ require 'chef/search/query'
7
+
8
+ module Chapp
9
+ class Database
10
+
11
+ APPS_DATA_BAG_NAME = "chapp_apps"
12
+ APP_ATTRIBUTES_DATA_BAG_NAME = "chapp_app_attributes"
13
+
14
+ PREFIX = "chapp"
15
+
16
+ def app_ids
17
+ apps_databag.keys
18
+ end
19
+
20
+ def app app_id
21
+
22
+ unless app_exists? app_id
23
+ raise Chapp::DB::AppNotExistsException.new, "App [#{app_id}] does not exist"
24
+ end
25
+
26
+ App.from_hash app_databag_item(app_id).raw_data["app"]
27
+ end
28
+
29
+ def app_exists? app_id
30
+ apps_databag.has_key? app_id
31
+ end
32
+
33
+ def connected_app_ids app_id
34
+ app_ids = Array.new
35
+
36
+ query = Chef::Search::Query.new
37
+ query.search APPS_DATA_BAG_NAME, "used_apps:#{app_id}" do |databag_item|
38
+ app = App.from_hash databag_item.raw_data["app"]
39
+ app_ids.push app.id
40
+ end
41
+
42
+ app_ids
43
+ end
44
+
45
+ def write_app app
46
+
47
+ # TODO Verify used_apps exist
48
+ # TODO Verify cookbooks exist
49
+
50
+ app_role_name = role_name app.id
51
+
52
+ attributes = app.node
53
+ attributes["chapp"]["app_id"] = app.id
54
+
55
+ # Build/Save role
56
+ role = Chef::Role.new
57
+ role.name app_role_name
58
+ role.description "Used to define the App [#{app.id}]"
59
+ role.default_attributes attributes.to_hash
60
+ role.run_list "recipe[chapp]", *app.pre_run_list, "recipe[#{app.cookbook}::#{app.recipe}]", *app.post_run_list, "recipe[chapp::publish_app_attributes]"
61
+ role.save
62
+
63
+ # Set run_list of app to role
64
+ app.run_list ["role[#{app_role_name}]"]
65
+
66
+ environment_name = "#{PREFIX}_env_#{app.id}"
67
+
68
+ # Build/Save environment
69
+ environment = Chef::Environment.new
70
+ environment.name environment_name
71
+ environment.description "Used to define the dependencies of App [#{app.id}]"
72
+
73
+ app.dependencies.each do |cookbook, version|
74
+ environment.cookbook cookbook, version
75
+ end
76
+
77
+ environment.save
78
+
79
+ # Set environment of app
80
+ app.environment environment_name
81
+
82
+ # Update app databag item
83
+ databag_item = app_databag_item app.id
84
+ databag_item.raw_data["app"] = app.to_hash
85
+ databag_item.save
86
+
87
+ end
88
+
89
+ def delete_app app_name
90
+ # TODO (not necessary for now)
91
+ # Delete role/environment, app databag item, app attribute databag item, app instances
92
+ end
93
+
94
+ def app_instances app_id
95
+ app_instances = Array.new
96
+
97
+ query = Chef::Search::Query.new
98
+ query.search(:node, "role:#{role_name app_id}") do |node|
99
+ app_instances.push Chapp::AppInstance.new(app_id, node.name, node["fqdn"])
100
+ end
101
+
102
+ app_instances
103
+ end
104
+
105
+ def write_app_instance app_instance
106
+ # NOOP (uses Chef Search)
107
+ end
108
+
109
+ def delete_app_instance app_instance
110
+ # TODO: Delete node/client (not necessary for now)
111
+ end
112
+
113
+ def app_attributes app_id
114
+ databag = app_attributes_databag
115
+
116
+ unless databag.has_key? app_id
117
+ raise Chapp::DB::AppAttributesNotExistsException.new, "Attributes for app [#{app_id}] do not exist"
118
+ end
119
+
120
+ app_attributes_databag_item(app_id).raw_data["app_attributes"]
121
+ end
122
+
123
+ def write_app_attributes app_id, app_attributes
124
+ databag_item = app_attributes_databag_item app_id
125
+ databag_item.raw_data["app_attributes"] = app_attributes
126
+ databag_item.save
127
+ end
128
+
129
+ def delete_app_attributes app_id
130
+ databag = app_attributes_databag
131
+
132
+ if databag.has_key? app_id
133
+ app_attributes_databag_item(app_id).destroy
134
+ end
135
+
136
+ end
137
+
138
+ private
139
+
140
+ def role_name app_id
141
+ "#{PREFIX}_role_#{app_id}"
142
+ end
143
+
144
+ def apps_databag
145
+ get_or_create_databag APPS_DATA_BAG_NAME
146
+ end
147
+
148
+ def app_databag_item app_id
149
+ load_or_build_databag_item apps_databag, APPS_DATA_BAG_NAME, app_id
150
+ end
151
+
152
+ def app_attributes_databag
153
+ get_or_create_databag APP_ATTRIBUTES_DATA_BAG_NAME
154
+ end
155
+
156
+ def app_attributes_databag_item app_id
157
+ load_or_build_databag_item app_attributes_databag, APP_ATTRIBUTES_DATA_BAG_NAME, app_id
158
+ end
159
+
160
+ def get_or_create_databag databag_name
161
+ databags = Chef::DataBag.list
162
+
163
+ unless databags.include? databag_name
164
+ # Create databag if it does not exist
165
+ databag = Chef::DataBag.new
166
+ databag.name databag_name
167
+ databag.save
168
+ end
169
+
170
+ Chef::DataBag.load databag_name
171
+ end
172
+
173
+ def load_or_build_databag_item databag, databag_name, databag_item_name
174
+ if databag.keys.include? databag_item_name
175
+ databag_item = Chef::DataBagItem.load databag_name, databag_item_name
176
+ else
177
+ # The databag item doesn't exist yet
178
+ databag_item = Chef::DataBagItem.new
179
+ databag_item.data_bag databag_name
180
+ databag_item.raw_data["id"] = databag_item_name
181
+
182
+ databag_item
183
+ end
184
+ end
185
+
186
+ end
187
+ end
@@ -0,0 +1,87 @@
1
+ require 'chapp'
2
+
3
+ module Chapp
4
+
5
+ class Wiring
6
+
7
+ attr_reader :announcements
8
+ attr_reader :node
9
+
10
+ def initialize app, db, node
11
+ @node = node
12
+ @announcements = Hash.new
13
+
14
+ @app = app
15
+ @db = db
16
+ @node = node
17
+
18
+ # Hash of used apps by type
19
+ @used_apps = Hash.new
20
+ @app.used_apps.each do |app_id|
21
+ used_app = db.app app_id
22
+
23
+ unless @used_apps.has_key? used_app.type
24
+ @used_apps[used_app.type] = Array.new
25
+ end
26
+
27
+ @used_apps[used_app.type] << used_app
28
+ end
29
+ end
30
+
31
+ def app_id
32
+ @app.id
33
+ end
34
+
35
+ def announce key, value
36
+ @announcements[key] = value
37
+ end
38
+
39
+ def used_app_ids
40
+ @app.used_apps
41
+ end
42
+
43
+ def used_app_attributes type
44
+
45
+ app_attributes = Hash.new
46
+
47
+ # TODO: Cache these values?
48
+ @used_apps[type].each do |app|
49
+ app_attributes[app.id] = @db.app_attributes app.id
50
+ end
51
+
52
+ app_attributes
53
+ end
54
+
55
+ def used_app_instances type
56
+ app_instances = Hash.new
57
+
58
+ # TODO: Cache these values?
59
+ @used_apps[type].each do |app|
60
+ app_instances[app.id] = @db.app_instances app.id
61
+ end
62
+
63
+ app_instances
64
+ end
65
+
66
+ def is_app_used? type
67
+ @used_apps.has_key? type
68
+ end
69
+
70
+ def connected_app_ids
71
+ # TODO: Cache these values?
72
+ @db.connected_app_ids @app.id
73
+ end
74
+
75
+ def app_instances app_id
76
+ # TODO: Cache these values?
77
+ @db.app_instances app_id
78
+ end
79
+
80
+ def app_attributes app_id
81
+ # TODO: Cache these values?
82
+ @db.app_attributes app_id
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,24 @@
1
+ require 'chef/knife'
2
+ require 'chapp'
3
+
4
+ class Chef
5
+ class Knife
6
+ class AppList < Chef::Knife
7
+
8
+ banner "knife app list (options)"
9
+ category "app"
10
+
11
+ # This method will be executed when you run this knife command.
12
+ def run
13
+
14
+ # Create or update the app
15
+ Chapp.database.app_ids.each do |app_id|
16
+ puts " * #{app_id}"
17
+ end
18
+
19
+ end
20
+
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,84 @@
1
+ require 'chef/knife'
2
+ require 'chapp'
3
+
4
+ class Chef
5
+ class Knife
6
+ class AppShow < Chef::Knife
7
+
8
+ banner "knife app show app_id (options)"
9
+ category "app"
10
+
11
+ # This method will be executed when you run this knife command.
12
+ def run
13
+
14
+ # Get Arguments
15
+ if @name_args.size != 1
16
+ ui.info("Please specify an app_id")
17
+ show_usage
18
+ exit 1
19
+ end
20
+
21
+ app_id = @name_args[0]
22
+
23
+ db = Chapp.database
24
+
25
+ app = db.app app_id
26
+ attributes = db.app_attributes app_id
27
+
28
+ puts "App :"
29
+ puts " id : #{app.id}"
30
+ puts " group : #{app.group}"
31
+ puts " name : #{app.name}"
32
+ puts " type : #{app.type}"
33
+ puts " cookbook : #{app.cookbook}"
34
+ puts " recipe : #{app.recipe}"
35
+
36
+ puts " used_apps :"
37
+ app.used_apps.each do |used_app_id|
38
+ puts " #{used_app_id}"
39
+ end
40
+
41
+ puts " node :"
42
+ print_hash app.node
43
+
44
+ puts " dependencies :"
45
+ app.dependencies.each do |cookbook, version_constraint|
46
+ puts " #{cookbook} #{version_constraint}"
47
+ end
48
+
49
+ puts " pre_run_list :"
50
+ app.pre_run_list.each do |run_list_item|
51
+ puts " #{run_list_item}"
52
+ end
53
+
54
+ puts " post_run_list :"
55
+ app.post_run_list.each do |run_list_item|
56
+ puts " #{run_list_item}"
57
+ end
58
+
59
+ puts ""
60
+
61
+ puts "App Attributes :"
62
+ print_hash attributes, 2
63
+
64
+ puts "App Instances :"
65
+ db.app_instances(app_id).each do |app_instance|
66
+ puts " #{app_instance.fqdn}"
67
+ end
68
+
69
+ end
70
+
71
+ def print_hash hash, spacing=4
72
+ hash.each do |key, value|
73
+ if !value.is_a? Hash
74
+ puts "#{" " * spacing}#{key} : #{value}"
75
+ else
76
+ puts "#{" " * spacing}#{key} : "
77
+ print_hash hash[key], (spacing + 2)
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,35 @@
1
+ require 'chef/knife'
2
+ require 'chapp'
3
+
4
+ class Chef
5
+ class Knife
6
+ class AppUpload < Chef::Knife
7
+
8
+ banner "knife app upload app_file (options)"
9
+ category "app"
10
+
11
+ # This method will be executed when you run this knife command.
12
+ def run
13
+
14
+ # Get Arguments
15
+ if @name_args.size != 1
16
+ ui.info("Please specify an app_file")
17
+ show_usage
18
+ exit 1
19
+ end
20
+
21
+ app_file = @name_args[0]
22
+
23
+ # Build app from file
24
+ app = Chapp::App.from_file app_file
25
+
26
+ # Write the app
27
+ Chapp.database.write_app app
28
+
29
+ puts "Uploaded app [#{app.id}]"
30
+ end
31
+
32
+
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chapp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Bryan Baugher
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '11.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '11.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: uuid
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yajl-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ description: A Chef Knife plugin that facilitates creating and configuring applications
70
+ in Chef
71
+ email: Bryan.Baugher@Cerner.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - Gemfile
77
+ - lib/chapp.rb
78
+ - lib/chapp/app.rb
79
+ - lib/chapp/app_instance.rb
80
+ - lib/chapp/database.rb
81
+ - lib/chapp/wiring.rb
82
+ - lib/chef/knife/app_list.rb
83
+ - lib/chef/knife/app_show.rb
84
+ - lib/chef/knife/app_upload.rb
85
+ homepage: http://github.com/bbaugher/chapp
86
+ licenses:
87
+ - The MIT License (MIT)
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project: nowarning
105
+ rubygems_version: 2.2.1
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: A Chef knife plugin for creating Chef Apps
109
+ test_files: []