Class: Bcome::Node::Base

Inherits:
Object
  • Object
show all
Includes:
Context, LoadingBar::Handler, Attributes, LocalMetaDataFactory, RegistryManagement, Tree, WorkspaceCommands, WorkspaceMenu
Defined in:
lib/objects/node/base.rb

Direct Known Subclasses

Collection, Inventory::Base, Server::Base

Constant Summary collapse

DEFAULT_IDENTIFIER =
'bcome'

Constants included from Draw

Draw::BLIP, Draw::BOTTOM_ANCHOR, Draw::BOX_BOTTOM_LEFT, Draw::BOX_BOTTOM_RIGHT, Draw::BOX_HORIZONTAL_LINE, Draw::BOX_SIDE, Draw::BOX_TOP_LEFT, Draw::BOX_TOP_RIGHT, Draw::BRANCH, Draw::INGRESS, Draw::LEFT_PADDING, Draw::MID_SHIPS

Constants included from LocalMetaDataFactory

LocalMetaDataFactory::META_DATA_FILE_PATH_PREFIX

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from LoadingBar::Handler

#cursor, #do_signal, #fork_process, #signal_failure, #signal_stop, #signal_success, #start_indicator, #stop_indicator, #wrap_indicator

Methods included from Tree

#build_tree, #deduce_tree_structure, #namespace_tree_line, #network_namespace_tree_data, #recurse_tree_lines, #routes, #routing_tree_data, #routing_tree_line, #to_nested_hash, #tree

Methods included from Draw

#box_it, #max_box_line_length

Methods included from RegistryManagement

#registry, #user_command_wrapper

Methods included from LocalMetaDataFactory

#do_create_metadata, #meta, #metadata, #metadata_for_namespace, #raw_metadata

Methods included from WorkspaceMenu

#item_spacing, #menu, #menu_group_names, #menu_item_spacing_length, #menu_items, #mode, #print_menu_items, #tab_spacing

Methods included from Attributes

#filters, #identifier, #network_data, #network_driver, #recurse_hash_data_for_instance_key, #ssh_data, #ssh_driver, #ssh_driver=

Methods included from WorkspaceCommands

#cd, #clear!, #disable, #disable!, #enable, #enable!, #interactive, #is_node_level_method?, #ls, #lsa, #method_in_registry?, #method_is_available_on_node?, #new_line, #parents, #ping, #pretty_description, #resource_identifiers, #run, #tree_descriptions, #visual_hierarchy, #workon

Methods included from Context

#current_context?, #irb_workspace=, #previous_irb_workspace=

Constructor Details

#initialize(params) ⇒ Base

Returns a new instance of Base.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/objects/node/base.rb', line 30

def initialize(params)
  @params = params
  @identifier = nil
  @description = nil
  @views = params[:views]
  @parent = params[:parent]
  @type = params[:type]
  @metadata = {}
  @nodes_loaded = false

  set_view_attributes if @views
  validate_attributes

  @original_identifier = @identifier

  ::Bcome::Registry::Loader.instance.set_command_group_for_node(self)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_sym, *arguments) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/objects/node/base.rb', line 52

def method_missing(method_sym, *arguments)
  raise Bcome::Exception::Generic, "undefined method '#{method_sym}' for #{self.class}" unless method_is_available_on_node?(method_sym)

  if resource_identifiers.include?(method_sym.to_s)
    method_sym.to_s
  elsif command = user_command_wrapper.command_for_console_command_name(method_sym)
    command.execute(self, arguments)
  else
    raise NameError, "Missing method #{method_sym} for #{self.class}"
  end
end

Instance Attribute Details

#identifier=(value) ⇒ Object (writeonly)

Sets the attribute identifier

Parameters:

  • value

    the value to set the attribute identifier to.



88
89
90
# File 'lib/objects/node/base.rb', line 88

def identifier=(value)
  @identifier = value
end

#paramsObject (readonly)

Returns the value of attribute params.



24
25
26
# File 'lib/objects/node/base.rb', line 24

def params
  @params
end

#parentObject (readonly)

Returns the value of attribute parent.



48
49
50
# File 'lib/objects/node/base.rb', line 48

def parent
  @parent
end

#viewsObject (readonly)

Returns the value of attribute views.



50
51
52
# File 'lib/objects/node/base.rb', line 50

def views
  @views
end

Class Method Details

.const_missing(constant) ⇒ Object



17
18
19
20
21
22
# File 'lib/objects/node/base.rb', line 17

def self.const_missing(constant)
  ## Hook for direct access to node level resources by constant name where
  ## cd ServerName should yield the same outcome as cd "ServerName"
  set_context = ::IRB.CurrentContext.workspace.main
  set_context.resource_for_identifier(constant.to_s) ? constant.to_s : super
end

Instance Method Details

#close_ssh_connectionsObject



267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/objects/node/base.rb', line 267

def close_ssh_connections
  # For every loaded server, we'll close any lingering ssh connection
  if @resources&.any?
    resources.pmap do |resource|
      if resource.is_a?(::Bcome::Node::Server::Base)
        resource.close_ssh_connection
      else
        resource.close_ssh_connections
      end
    end
  end
  nil
end

#collection?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/objects/node/base.rb', line 68

def collection?
  false
end

#data_print_from_hash(data, heading) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/objects/node/base.rb', line 287

def data_print_from_hash(data, heading)
  puts "\n#{heading.title}"
  puts ''

  if data.keys.any?
    data.each do |key, value|
      puts "#{key.to_s.resource_key}: #{value.to_s.informational}"
    end
  else
    puts 'No values found'.warning
  end
  puts ''
end

#enabled_menu_itemsObject



80
81
82
# File 'lib/objects/node/base.rb', line 80

def enabled_menu_items
  %i[ls lsa workon enable disable enable! disable! run tree ping put put_str rsync cd meta registry interactive execute_script]
end

#execute_local(command) ⇒ Object



281
282
283
284
285
# File 'lib/objects/node/base.rb', line 281

def execute_local(command)
  puts "(local) > #{command}" unless ::Bcome::Orchestrator.instance.command_output_silenced?
  system(command)
  puts ''
end

#execute_script(script_name) ⇒ Object



138
139
140
141
142
143
144
145
# File 'lib/objects/node/base.rb', line 138

def execute_script(script_name)
  results = {}
  machines.pmap do |machine|
    command = machine.execute_script(script_name)
    results[machine.namespace] = command
  end
  results
end

#has_parent?Boolean

Returns:

  • (Boolean)


251
252
253
# File 'lib/objects/node/base.rb', line 251

def has_parent?
  !@parent.nil?
end

#has_proxy?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/objects/node/base.rb', line 84

def has_proxy?
  ssh_driver.has_proxy?
end

#hide?Boolean

Returns:

  • (Boolean)


147
148
149
150
151
# File 'lib/objects/node/base.rb', line 147

def hide?
  return true if @views.key?(:hidden) && @views[:hidden]

  false
end

#inspectObject



13
14
15
# File 'lib/objects/node/base.rb', line 13

def inspect
  "<##{self.class}: #{namespace} @network_driver=#{network_driver}>"
end

#inventory?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/objects/node/base.rb', line 72

def inventory?
  false
end

#invoke(method_name, arguments = []) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/objects/node/base.rb', line 201

def invoke(method_name, arguments = [])
  if method_is_available_on_node?(method_name)
    if respond_to?(method_name)
      # Invoke a method on node that's defined by the system
      begin
        if arguments&.any?
          send(method_name, *arguments)
        else
          send(method_name)
        end
      rescue ArgumentError => e
        raise ::Bcome::Exception::ArgumentErrorInvokingMethodFromCommmandLine, method_name + " error message - #{e.message}"
      end
    else
      # Invoke a user defined (registry) method
      command = user_command_wrapper.command_for_console_command_name(method_name.to_sym)
      command.execute(self, arguments)
    end
  else
    # Final crumb is neither a node level context nor an executable method on the penultimate node level context
    raise ::Bcome::Exception::InvalidBreadcrumb, "Method '#{method_name}' is not available on bcome node of type #{self.class}, at namespace #{namespace}"
  end
end

#is_top_level_node?Boolean

Returns:

  • (Boolean)


255
256
257
# File 'lib/objects/node/base.rb', line 255

def is_top_level_node?
  !has_parent?
end

#keyed_namespaceObject



246
247
248
249
# File 'lib/objects/node/base.rb', line 246

def keyed_namespace
  splits = namespace.split(':')
  splits[1..splits.size].join(':')
end

#list_attributesObject



259
260
261
262
263
264
265
# File 'lib/objects/node/base.rb', line 259

def list_attributes
  {
    "Identifier": :identifier,
    "Description": :description,
    "Type": :type
  }
end

#list_keyObject



197
198
199
# File 'lib/objects/node/base.rb', line 197

def list_key
  :view
end

#namespaceObject



242
243
244
# File 'lib/objects/node/base.rb', line 242

def namespace
  "#{parent ? "#{parent.namespace}:" : ''}#{identifier}"
end

#no_nodes?Boolean

Returns:

  • (Boolean)


179
180
181
# File 'lib/objects/node/base.rb', line 179

def no_nodes?
  !resources || resources.empty?
end

#nodes_loaded!Object



189
190
191
# File 'lib/objects/node/base.rb', line 189

def nodes_loaded!
  @nodes_loaded = true
end

#nodes_loaded?Boolean

Returns:

  • (Boolean)


183
184
185
186
187
# File 'lib/objects/node/base.rb', line 183

def nodes_loaded?
  # resources.any? # This was buggy:  an inventory may validly contain no resources. This does not mean that we haven't attempted to load them
  # we no explicitly set a flag for when we've loaded nodes. This will prevents uneccessary lookups over the wire
  @nodes_loaded
end

#prompt_breadcrumbObject



234
235
236
237
238
239
240
# File 'lib/objects/node/base.rb', line 234

def prompt_breadcrumb
  "#{has_parent? ? "#{parent.prompt_breadcrumb}> " : ''}#{if current_context?
                                                            has_parent? ? identifier.terminal_prompt : identifier
                                                          else
                                                            identifier
                                                          end}"
end

#proxyObject



90
91
92
# File 'lib/objects/node/base.rb', line 90

def proxy
  ssh_driver.proxy
end

#proxy_chainObject



94
95
96
# File 'lib/objects/node/base.rb', line 94

def proxy_chain
  ssh_driver.proxy_chain
end


98
99
100
# File 'lib/objects/node/base.rb', line 98

def proxy_chain_link
  @proxy_chain_link ||= ::Bcome::Ssh::ProxyChainLink.new(self)
end

#put(local_path, remote_path, connect = true) ⇒ Object



121
122
123
124
125
126
127
128
# File 'lib/objects/node/base.rb', line 121

def put(local_path, remote_path, connect = true)
  ssh_connect if connect # Initiate connect at highest namespace level

  scoped_resources.each do |resource|
    resource.put(local_path, remote_path, false)
  end
  nil
end

#put_str(string, remote_path, connect = true) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/objects/node/base.rb', line 130

def put_str(string, remote_path, connect = true)
  ssh_connect if connect # Initiate connect at highest namespace level
  scoped_resources.pmap do |resource|
    resource.put_str(string, remote_path, false)
  end
  nil
end

#recurse_resource_for_identifier(identifier) ⇒ Object



229
230
231
232
# File 'lib/objects/node/base.rb', line 229

def recurse_resource_for_identifier(identifier)
  resource = resource_for_identifier(identifier)
  resource || (has_parent? ? parent.recurse_resource_for_identifier(identifier) : nil)
end

#requires_description?Boolean

Returns:

  • (Boolean)


171
172
173
# File 'lib/objects/node/base.rb', line 171

def requires_description?
  true
end

#requires_type?Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/objects/node/base.rb', line 175

def requires_type?
  true
end

#resource_for_identifier(identifier) ⇒ Object



225
226
227
# File 'lib/objects/node/base.rb', line 225

def resource_for_identifier(identifier)
  resources.for_identifier(identifier)
end

#resourcesObject



193
194
195
# File 'lib/objects/node/base.rb', line 193

def resources
  @resources ||= ::Bcome::Node::Resources::Base.new
end

#rsync(local_path, remote_path) ⇒ Object



114
115
116
117
118
119
# File 'lib/objects/node/base.rb', line 114

def rsync(local_path, remote_path)
  scoped_resources.each do |resource|
    resource.rsync(local_path, remote_path)
  end
  nil
end

#scoped_resourcesObject



102
103
104
105
# File 'lib/objects/node/base.rb', line 102

def scoped_resources
  # Active & not hidden
  resources.active.reject(&:hide?)
end

#scp(local_path, remote_path) ⇒ Object



107
108
109
110
111
112
# File 'lib/objects/node/base.rb', line 107

def scp(local_path, remote_path)
  scoped_resources.each do |resource|
    resource.put(local_path, remote_path)
  end
  nil
end

#server?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/objects/node/base.rb', line 76

def server?
  false
end

#ssh_connect(params = {}) ⇒ Object



64
65
66
# File 'lib/objects/node/base.rb', line 64

def ssh_connect(params = {})
  ::Bcome::Ssh::Connector.connect(self, params)
end

#validate_attributesObject



153
154
155
156
157
# File 'lib/objects/node/base.rb', line 153

def validate_attributes
  validate_identifier
  raise ::Bcome::Exception::MissingDescriptionOnView, views.inspect if requires_description? && !defined?(:description)
  raise ::Bcome::Exception::MissingTypeOnView, views.inspect if requires_type? && !defined?(:type)
end

#validate_identifierObject



159
160
161
162
163
164
165
166
167
168
169
# File 'lib/objects/node/base.rb', line 159

def validate_identifier
  @identifier = DEFAULT_IDENTIFIER.dup if is_top_level_node? && !@identifier && !is_a?(::Bcome::Node::Server::Base)

  @identifier ||= "NO-ID_#{Time.now.to_i}".dup

  # raise ::Bcome::Exception::MissingIdentifierOnView.new(@views.inspect) unless @identifier
  @identifier.gsub!(/\s/, '_') # Remove whitespace
  @identifier.gsub!('-', '_') # change hyphens to undescores, hyphens don't play well in var names in irb

  # raise ::Bcome::Exception::InvalidIdentifier.new("'#{@identifier}' contains whitespace") if @identifier =~ /\s/
end