bcome 0.7.0 → 1.0.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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bcome +8 -39
  3. data/lib/bcome.rb +12 -3
  4. data/lib/objects/bcome/version.rb +3 -0
  5. data/lib/objects/bootup.rb +81 -0
  6. data/lib/objects/command/local.rb +40 -0
  7. data/lib/objects/config_factory.rb +36 -0
  8. data/lib/objects/driver/base.rb +30 -0
  9. data/lib/objects/driver/bucket.rb +20 -0
  10. data/lib/objects/driver/ec2.rb +44 -0
  11. data/lib/objects/driver/static.rb +4 -0
  12. data/lib/objects/exception/argument_error_invoking_method_from_command_line.rb +7 -0
  13. data/lib/objects/exception/base.rb +15 -0
  14. data/lib/objects/exception/can_only_subselect_on_inventory.rb +7 -0
  15. data/lib/objects/exception/cannot_find_internal_registry_klass.rb +7 -0
  16. data/lib/objects/exception/cannot_find_subselection_parent.rb +7 -0
  17. data/lib/objects/exception/cant_find_key_in_cloud_tags.rb +7 -0
  18. data/lib/objects/exception/cant_find_key_in_metadata.rb +7 -0
  19. data/lib/objects/exception/cant_find_proxy_host_by_identifier.rb +7 -0
  20. data/lib/objects/exception/cant_find_proxy_host_by_namespace.rb +7 -0
  21. data/lib/objects/exception/could_not_initiate_ssh_connection.rb +7 -0
  22. data/lib/objects/exception/could_not_initiate_ssh_connection_through_backend_proxy.rb +7 -0
  23. data/lib/objects/exception/deprecation_warning.rb +11 -0
  24. data/lib/objects/exception/duplicate_command_line_argument_key.rb +7 -0
  25. data/lib/objects/exception/ec2_driver_missing_provisioning_region.rb +7 -0
  26. data/lib/objects/exception/failed_to_run_local_command.rb +7 -0
  27. data/lib/objects/exception/interactive_session_halt.rb +4 -0
  28. data/lib/objects/exception/invalid_bcome_breadcrumb.rb +7 -0
  29. data/lib/objects/exception/invalid_breadcrumb.rb +7 -0
  30. data/lib/objects/exception/invalid_context_command.rb +7 -0
  31. data/lib/objects/exception/invalid_identifier.rb +7 -0
  32. data/lib/objects/exception/invalid_machines_cache_config.rb +7 -0
  33. data/lib/objects/exception/invalid_matcher_query.rb +7 -0
  34. data/lib/objects/exception/invalid_meta_data_config.rb +7 -0
  35. data/lib/objects/exception/invalid_network_config.rb +7 -0
  36. data/lib/objects/exception/invalid_network_driver_type.rb +7 -0
  37. data/lib/objects/exception/invalid_proxy_config.rb +7 -0
  38. data/lib/objects/exception/invalid_regexp_matcher_in_registry.rb +7 -0
  39. data/lib/objects/exception/invalid_registry_arguments_type.rb +7 -0
  40. data/lib/objects/exception/invalid_registry_data_config.rb +7 -0
  41. data/lib/objects/exception/invalid_restriction_key_in_registry.rb +7 -0
  42. data/lib/objects/exception/invalid_ssh_config.rb +7 -0
  43. data/lib/objects/exception/inventories_cannot_have_subviews.rb +7 -0
  44. data/lib/objects/exception/malformed_command_line_arguments.rb +7 -0
  45. data/lib/objects/exception/method_invocation_requires_parameter.rb +7 -0
  46. data/lib/objects/exception/method_name_conflict_in_registry.rb +7 -0
  47. data/lib/objects/exception/missing_argument_for_registry_command.rb +7 -0
  48. data/lib/objects/exception/missing_description_on_view.rb +7 -0
  49. data/lib/objects/exception/missing_execute_on_registry_object.rb +7 -0
  50. data/lib/objects/exception/missing_identifier_on_view.rb +7 -0
  51. data/lib/objects/exception/missing_ip_address_on_server.rb +7 -0
  52. data/lib/objects/exception/missing_network_config.rb +7 -0
  53. data/lib/objects/exception/missing_params_for_rsync.rb +7 -0
  54. data/lib/objects/exception/missing_params_for_scp.rb +7 -0
  55. data/lib/objects/exception/missing_subselection_key.rb +7 -0
  56. data/lib/objects/exception/missing_type_on_view.rb +7 -0
  57. data/lib/objects/exception/no_node_found_for_breadcrumb.rb +7 -0
  58. data/lib/objects/exception/no_node_named_by_identifier.rb +7 -0
  59. data/lib/objects/exception/node_identifiers_must_be_unique.rb +7 -0
  60. data/lib/objects/exception/orchestration_script_does_not_exist.rb +7 -0
  61. data/lib/objects/exception/proxy_host_node_does_not_have_public_ip_address.rb +7 -0
  62. data/lib/objects/exception/unknown_method_for_namespace.rb +7 -0
  63. data/lib/objects/interactive/session.rb +45 -0
  64. data/lib/objects/interactive/session_item/base.rb +36 -0
  65. data/lib/objects/interactive/session_item/capture_input.rb +20 -0
  66. data/lib/objects/interactive/session_item/transparent_ssh.rb +111 -0
  67. data/lib/objects/modules/context.rb +13 -0
  68. data/lib/objects/modules/registry_management.rb +14 -0
  69. data/lib/objects/modules/ui_output.rb +9 -0
  70. data/lib/objects/modules/workspace_commands.rb +198 -0
  71. data/lib/objects/modules/workspace_menu.rb +128 -0
  72. data/lib/objects/node/attributes.rb +47 -0
  73. data/lib/objects/node/base.rb +248 -0
  74. data/lib/objects/node/cache_handler.rb +24 -0
  75. data/lib/objects/node/collection.rb +51 -0
  76. data/lib/objects/node/factory.rb +108 -0
  77. data/lib/objects/node/inventory/base.rb +88 -0
  78. data/lib/objects/node/inventory/defined.rb +112 -0
  79. data/lib/objects/node/inventory/subselect.rb +54 -0
  80. data/lib/objects/node/meta/base.rb +36 -0
  81. data/lib/objects/node/meta/cloud.rb +4 -0
  82. data/lib/objects/node/meta/local.rb +4 -0
  83. data/lib/objects/node/meta_data_factory.rb +23 -0
  84. data/lib/objects/node/meta_data_loader.rb +32 -0
  85. data/lib/objects/node/resources/base.rb +98 -0
  86. data/lib/objects/node/resources/inventory.rb +25 -0
  87. data/lib/objects/node/resources/sub_inventory.rb +56 -0
  88. data/lib/objects/node/server/base.rb +218 -0
  89. data/lib/objects/node/server/dynamic.rb +39 -0
  90. data/lib/objects/node/server/static.rb +31 -0
  91. data/lib/objects/orchestration/base.rb +13 -0
  92. data/lib/objects/orchestrator.rb +24 -0
  93. data/lib/objects/parser/bread_crumb.rb +31 -0
  94. data/lib/objects/progress_bar.rb +30 -0
  95. data/lib/objects/registry/arguments/base.rb +36 -0
  96. data/lib/objects/registry/arguments/command_line.rb +35 -0
  97. data/lib/objects/registry/arguments/console.rb +15 -0
  98. data/lib/objects/registry/command/base.rb +66 -0
  99. data/lib/objects/registry/command/external.rb +55 -0
  100. data/lib/objects/registry/command/group.rb +76 -0
  101. data/lib/objects/registry/command/internal.rb +34 -0
  102. data/lib/objects/registry/command_list.rb +33 -0
  103. data/lib/objects/registry/loader.rb +70 -0
  104. data/lib/objects/ssh/bootstrap.rb +19 -0
  105. data/lib/objects/ssh/command.rb +46 -0
  106. data/lib/objects/ssh/command_exec.rb +65 -0
  107. data/lib/objects/ssh/connection_handler.rb +101 -0
  108. data/lib/objects/ssh/driver.rb +204 -0
  109. data/lib/objects/ssh/proxy_data.rb +56 -0
  110. data/lib/objects/ssh/script_exec.rb +43 -0
  111. data/lib/objects/system/local.rb +30 -0
  112. data/lib/objects/workspace.rb +75 -0
  113. data/patches/irb.rb +20 -7
  114. data/patches/string.rb +75 -0
  115. data/patches/string_stylesheet.rb +61 -0
  116. metadata +175 -93
  117. data/bin/bcome-bash-setup +0 -18
  118. data/bin/bcome-setup +0 -43
  119. data/bin/boot.rb +0 -148
  120. data/bin/boot_no_shell.rb +0 -3
  121. data/filters/ec2_filter.rb +0 -12
  122. data/lib/bcome/version.rb +0 -3
  123. data/lib/become_object.rb +0 -111
  124. data/lib/boot.rb +0 -13
  125. data/lib/command.rb +0 -56
  126. data/lib/context_functions.rb +0 -65
  127. data/lib/filters/base.rb +0 -10
  128. data/lib/filters/ec2_filter.rb +0 -4
  129. data/lib/functions.rb +0 -70
  130. data/lib/helpers/command_helper.rb +0 -13
  131. data/lib/helpers/environment_ssh.rb +0 -122
  132. data/lib/helpers/fog_helper.rb +0 -108
  133. data/lib/helpers/instance_command.rb +0 -71
  134. data/lib/helpers/instance_ssh.rb +0 -83
  135. data/lib/helpers/selections.rb +0 -117
  136. data/lib/interactive/interactive_session_halt.rb +0 -4
  137. data/lib/interactive/session.rb +0 -44
  138. data/lib/interactive/session_item/base.rb +0 -30
  139. data/lib/interactive/session_item/transparent_ssh.rb +0 -133
  140. data/lib/nodes/base.rb +0 -60
  141. data/lib/nodes/environment.rb +0 -30
  142. data/lib/nodes/estate.rb +0 -44
  143. data/lib/nodes/instance.rb +0 -94
  144. data/lib/nodes/platform.rb +0 -17
  145. data/lib/nodes/view.rb +0 -31
  146. data/lib/object.rb +0 -21
  147. data/lib/orchestrator/command_group/base.rb +0 -56
  148. data/lib/orchestrator/command_group/custom.rb +0 -13
  149. data/lib/orchestrator/command_group/direct.rb +0 -53
  150. data/lib/orchestrator/direct_command/group.rb +0 -21
  151. data/lib/orchestrator/direct_command/instance.rb +0 -19
  152. data/lib/orchestrator/factory.rb +0 -38
  153. data/lib/orchestrator/loader.rb +0 -47
  154. data/lib/orchestrator/node_target/all.rb +0 -14
  155. data/lib/orchestrator/node_target/all_excluding_roles.rb +0 -14
  156. data/lib/orchestrator/node_target/all_with_roles.rb +0 -14
  157. data/lib/orchestrator/node_target/base.rb +0 -43
  158. data/lib/orchestrator/node_target/single.rb +0 -12
  159. data/lib/orchestrator/recipe.rb +0 -60
  160. data/lib/orchestrator/registry.rb +0 -37
  161. data/lib/orchestrator/validate_and_set.rb +0 -10
  162. data/lib/patches/string.rb +0 -86
  163. data/lib/progress_bar.rb +0 -31
  164. data/lib/render_irb.rb +0 -53
  165. data/lib/scp.rb +0 -40
  166. data/lib/ssh.rb +0 -51
  167. data/lib/stack/base.rb +0 -148
  168. data/lib/stack/environment.rb +0 -222
  169. data/lib/stack/estate.rb +0 -50
  170. data/lib/stack/instance.rb +0 -130
  171. data/lib/stack/platform.rb +0 -74
  172. data/lib/stack/view.rb +0 -56
  173. data/lib/workspace_context.rb +0 -40
@@ -0,0 +1,88 @@
1
+ module Bcome::Node::Inventory
2
+ class Base < ::Bcome::Node::Base
3
+ def initialize(*params)
4
+ super
5
+ raise Bcome::Exception::InventoriesCannotHaveSubViews, @views if @views[:views] && !@views[:views].empty?
6
+ end
7
+
8
+ def meta_matches(matchers)
9
+ data_wrapper = :metadata
10
+ matches_for(data_wrapper, matchers)
11
+ end
12
+
13
+ def cloud_matches(matchers)
14
+ data_wrapper = :cloud_tags
15
+ matches_for(data_wrapper, matchers)
16
+ end
17
+
18
+ def machine_by_identifier(identifier)
19
+ resources.active.select { |machine| machine.identifier == identifier }.first
20
+ end
21
+
22
+ def matches_for(data_wrapper, matchers)
23
+ resources.active.select do |machine|
24
+ machine.send(data_wrapper).has_key_and_value?(matchers)
25
+ end
26
+ end
27
+
28
+ def enabled_menu_items
29
+ super + %i[ssh]
30
+ end
31
+
32
+ def menu_items
33
+ base_items = super.dup
34
+ base_items[:ssh] = {
35
+ description: 'ssh directly into a resource',
36
+ usage: 'ssh identifier',
37
+ console_only: true
38
+ }
39
+
40
+ base_items
41
+ end
42
+
43
+ def resources
44
+ @resources ||= ::Bcome::Node::Resources::Inventory.new
45
+ end
46
+
47
+ def ssh(identifier = nil)
48
+ direct_invoke_server(:ssh, identifier)
49
+ end
50
+
51
+ def tags(identifier = nil)
52
+ direct_invoke_server(:tags, identifier)
53
+ end
54
+
55
+ def direct_invoke_server(method, identifier)
56
+ unless identifier
57
+ puts "\nPlease provide a machine identifier, e.g. #{method} machinename\n".warning unless identifier
58
+ return
59
+ end
60
+
61
+ if resource = resources.for_identifier(identifier)
62
+ resource.send(method)
63
+ else
64
+ raise Bcome::Exception::InvalidBreadcrumb, "Cannot find a node named '#{identifier}'"
65
+ end
66
+ end
67
+
68
+ def cache_nodes_in_memory
69
+ @cache_handler.do_cache_nodes!
70
+ end
71
+
72
+ def list_key
73
+ :server
74
+ end
75
+
76
+ def machines
77
+ @resources.active
78
+ end
79
+
80
+ def inventory?
81
+ true
82
+ end
83
+
84
+ def override_server_identifier?
85
+ !@override_identifier.nil?
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,112 @@
1
+ module Bcome::Node::Inventory
2
+ class Defined < ::Bcome::Node::Inventory::Base
3
+ MACHINES_CACHE_PATH = 'machines-cache.yml'.freeze
4
+
5
+ def self.to_s
6
+ 'inventory'
7
+ end
8
+
9
+ attr_reader :dynamic_nodes_loaded
10
+
11
+ def initialize(*params)
12
+ @load_machines_from_cache = false
13
+ @cache_handler = ::Bcome::Node::CacheHandler.new(self)
14
+ super
15
+ end
16
+
17
+ def enabled_menu_items
18
+ super + %i[save reload]
19
+ end
20
+
21
+ def menu_items
22
+ base_items = super.dup
23
+
24
+ base_items[:reload] = {
25
+ description: "Restock this inventory from remote (hit 'save' after to persist)",
26
+ console_only: true
27
+ }
28
+ base_items
29
+ end
30
+
31
+ def reload
32
+ do_reload
33
+ puts "\nDone. Hit 'ls' to see the refreshed inventory.\n".informational
34
+ end
35
+
36
+ def set_static_servers
37
+ if raw_static_machines_from_cache
38
+ raw_static_machines_from_cache.each do |server_config|
39
+ resources << ::Bcome::Node::Server::Static.new(views: server_config, parent: self)
40
+ end
41
+ end
42
+ end
43
+
44
+ def raw_static_machines_from_cache
45
+ load_machines_config[namespace.to_sym]
46
+ end
47
+
48
+ def machines_cache_path
49
+ "#{::Bcome::Node::Factory::CONFIG_PATH}/#{MACHINES_CACHE_PATH}"
50
+ end
51
+
52
+ def mark_as_cached!
53
+ data = ::Bcome::Node::Factory.instance.load_estate_config
54
+ data[namespace.to_sym][:load_machines_from_cache] = true
55
+ ::Bcome::Node::Factory.instance.rewrite_estate_config(data)
56
+ end
57
+
58
+ def save
59
+ @answer = ::Bcome::Interactive::Session.run(self,
60
+ :capture_input, terminal_prompt: "\nAre you sure you want to cache these machines (saving will overwrite any previous selections) [Y|N] ? ")
61
+
62
+ if @answer && @answer == 'Y'
63
+ cache_nodes_in_memory
64
+ data = load_machines_config
65
+ data[namespace] = views[:static_servers]
66
+
67
+ File.open(machines_cache_path, 'w') do |file|
68
+ file.write data.to_yaml
69
+ end
70
+ mark_as_cached!
71
+ puts "Machines have been cached for node #{namespace}".informational
72
+ else
73
+ puts 'Nothing saved'.warning
74
+ end
75
+ end
76
+
77
+ def load_machines_config
78
+ config = YAML.load_file(machines_cache_path).deep_symbolize_keys
79
+ return config
80
+ rescue ArgumentError, Psych::SyntaxError
81
+ raise Bcome::Exception::InvalidMachinesCacheConfig, 'Invalid yaml in config'
82
+ rescue Errno::ENOENT
83
+ return {}
84
+ end
85
+
86
+ def cache_nodes_in_memory
87
+ @cache_handler.do_cache_nodes!
88
+ end
89
+
90
+ def do_reload
91
+ resources.unset!
92
+ load_dynamic_nodes
93
+ end
94
+
95
+ def load_nodes
96
+ set_static_servers
97
+ load_dynamic_nodes unless @load_machines_from_cache
98
+ end
99
+
100
+ def load_dynamic_nodes
101
+ raw_servers = fetch_server_list
102
+ raw_servers.each do |raw_server|
103
+ resources << ::Bcome::Node::Server::Dynamic.new_from_fog_instance(raw_server, self)
104
+ end
105
+ end
106
+
107
+ def fetch_server_list
108
+ return [] unless network_driver
109
+ network_driver.fetch_server_list(filters)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,54 @@
1
+ module Bcome::Node::Inventory
2
+ class Subselect < ::Bcome::Node::Inventory::Base
3
+ def initialize(*params)
4
+ super
5
+ raise Bcome::Exception::MissingSubselectionKey, @views unless @views[:subselect_from]
6
+ update_nodes
7
+ end
8
+
9
+ def resources
10
+ @resources ||= do_set_resources
11
+ end
12
+
13
+ def update_nodes
14
+ resources.update_nodes(self)
15
+ end
16
+
17
+ def do_set_resources
18
+ ::Bcome::Node::Resources::SubselectInventory.new(parent_inventory: parent_inventory, filters: filters)
19
+ end
20
+
21
+ def nodes_loaded?
22
+ true
23
+ end
24
+
25
+ def filters
26
+ # Flex point for filters, as obviously we need to support more than just ec2 filtering eventually
27
+ @views[:filters] ? @views[:filters] : {}
28
+ end
29
+
30
+ def self.to_s
31
+ 'sub-inventory'
32
+ end
33
+
34
+ def do_reload
35
+ parent_inventory.do_reload
36
+ resources.run_subselect
37
+ update_nodes
38
+ end
39
+
40
+ private
41
+
42
+ def parent_inventory
43
+ @parent_inventory ||= load_parent_inventory
44
+ end
45
+
46
+ def load_parent_inventory
47
+ parent_crumb = @views[:subselect_from]
48
+ parent = ::Bcome::Node::Factory.instance.bucket[parent_crumb]
49
+ raise Bcome::Exception::CannotFindSubselectionParent, "for key '#{parent_crumb}'" unless parent
50
+ raise Bcome::Exception::CanOnlySubselectOnInventory, "breadcrumb'#{parent_crumb}' represents a #{parent.class}'" unless parent.inventory?
51
+ parent
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,36 @@
1
+ module Bcome::Node::Meta
2
+ class Base
3
+ attr_reader :data
4
+
5
+ def initialize(data)
6
+ @data = data
7
+ end
8
+
9
+ def has_key_and_value?(matchers)
10
+ matchers[:values] = [matchers[:values]] if matchers[:values] && !matchers[:values].is_a?(Array)
11
+
12
+ raise Bcome::Exception::InvalidMatcherQuery unless matchers[:key] && matchers[:values].is_a?(Array)
13
+ key = matchers[:key].to_sym
14
+ values = matchers[:values]
15
+ @data.key?(key) && values.include?(@data[key])
16
+ end
17
+
18
+ def dump
19
+ @data.each do |k, v|
20
+ puts "#{k} => #{v.resource_value}"
21
+ end
22
+ end
23
+
24
+ def all
25
+ @data
26
+ end
27
+
28
+ def fetch(key)
29
+ if @data.key?(key)
30
+ @data[key]
31
+ else
32
+ raise Bcome::Exception::CantFindKeyInMetadata, key unless @data.key?(key)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ module Bcome::Node::Meta
2
+ class Cloud < Bcome::Node::Meta::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Bcome::Node::Meta
2
+ class Local < Bcome::Node::Meta::Base
3
+ end
4
+ end
@@ -0,0 +1,23 @@
1
+ module Bcome::Node::LocalMetaDataFactory
2
+ META_DATA_FILE_PATH_PREFIX = 'bcome/metadata'.freeze
3
+
4
+ def metadata
5
+ @node_metadata ||= do_create_metadata
6
+ end
7
+
8
+ def do_create_metadata
9
+ ::Bcome::Node::Meta::Local.new(raw_metadata)
10
+ end
11
+
12
+ def meta
13
+ data_print_from_hash(raw_metadata, 'Metadata')
14
+ end
15
+
16
+ def raw_metadata
17
+ has_parent? ? parent.raw_metadata.merge(metadata_for_namespace) : metadata_for_namespace
18
+ end
19
+
20
+ def metadata_for_namespace
21
+ ::Bcome::Node::MetaDataLoader.instance.data_for_namespace(namespace)
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ module Bcome::Node
2
+ class MetaDataLoader
3
+ include ::Singleton
4
+
5
+ META_DATA_FILE_PATH_PREFIX = 'bcome/metadata'.freeze
6
+
7
+ def initialize
8
+ @all_metadata_filenames = Dir["#{META_DATA_FILE_PATH_PREFIX}/*"]
9
+ end
10
+
11
+ def data
12
+ @data ||= do_load
13
+ end
14
+
15
+ def data_for_namespace(namespace)
16
+ data[namespace.to_sym] ? data[namespace.to_sym] : {}
17
+ end
18
+
19
+ def do_load
20
+ all_meta_data = {}
21
+ @all_metadata_filenames.each do |filename|
22
+ begin
23
+ filedata = YAML.load_file(filename)
24
+ all_meta_data.deep_merge!(filedata)
25
+ rescue Psych::SyntaxError => e
26
+ raise Bcome::Exception::InvalidMetaDataConfig, "Error: #{e.message}"
27
+ end
28
+ end
29
+ all_meta_data
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,98 @@
1
+ module Bcome::Node::Resources
2
+ class Base
3
+ include Enumerable
4
+
5
+ attr_reader :nodes
6
+
7
+ def initialize(*_params)
8
+ @nodes = []
9
+ @disabled_resources = []
10
+ end
11
+
12
+ def each
13
+ @nodes.each { |node| yield(node) }
14
+ end
15
+
16
+ def <<(node)
17
+ existing_node = for_identifier(node.identifier)
18
+ if existing_node
19
+ exception_message = "#{node.identifier} is not unique within namespace #{node.parent.namespace}"
20
+ raise Bcome::Exception::NodeIdentifiersMustBeUnique, exception_message
21
+ end
22
+ @nodes << node
23
+ end
24
+
25
+ def clear!
26
+ @disabled_resources = []
27
+ end
28
+ alias enable! clear!
29
+
30
+ def do_disable(identifier)
31
+ if identifier.is_a?(Array)
32
+ identifier.each { |id| disable(id) }
33
+ else
34
+ disable(identifier)
35
+ end
36
+ nil
37
+ end
38
+
39
+ def do_enable(identifier)
40
+ if identifier.is_a?(Array)
41
+ identifier.each { |id| enable(id) }
42
+ else
43
+ enable(identifier)
44
+ end
45
+ nil
46
+ end
47
+
48
+ def disable!
49
+ @disabled_resources = @nodes
50
+ end
51
+
52
+ def disable(identifier)
53
+ resource = for_identifier(identifier)
54
+ raise Bcome::Exception::NoNodeNamedByIdentifier, identifier unless resource
55
+ @disabled_resources << resource unless @disabled_resources.include?(resource)
56
+ end
57
+
58
+ def enable(identifier)
59
+ resource = for_identifier(identifier)
60
+ raise Bcome::Exception::NoNodeNamedByIdentifier, identifier unless resource
61
+ @disabled_resources -= [resource]
62
+ end
63
+
64
+ def clear!
65
+ @disabled_resources = []
66
+ nil
67
+ end
68
+
69
+ def active
70
+ @nodes - @disabled_resources
71
+ end
72
+
73
+ def is_active_resource?(resource)
74
+ active.include?(resource)
75
+ end
76
+
77
+ def for_identifier(identifier)
78
+ resource = @nodes.select { |node| node.identifier == identifier }.first
79
+ resource
80
+ end
81
+
82
+ def empty?
83
+ @nodes.empty?
84
+ end
85
+
86
+ def has_active_nodes?
87
+ active.any?
88
+ end
89
+
90
+ def size
91
+ @nodes.size
92
+ end
93
+
94
+ def first
95
+ @nodes.first
96
+ end
97
+ end
98
+ end