chapp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []