Class: Cheftacular::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/cheftacular/parser.rb

Instance Method Summary collapse

Constructor Details

#initialize(options, config) ⇒ Parser



4
5
6
# File 'lib/cheftacular/parser.rb', line 4

def initialize options, config
  @options, @config  = options, config
end

Instance Method Details

#array_of_nodes_contains_node_name?(nodes, node_name, names = []) ⇒ Boolean



121
122
123
124
125
# File 'lib/cheftacular/parser.rb', line 121

def array_of_nodes_contains_node_name? nodes, node_name, names=[]
  nodes.each { |node| names << node['name'] }

  names.include? node_name
end

#exclude_nodes(nodes, statement_arr, only_one_node = false, ret_arr = []) ⇒ Object

parse nodes out of array based on hash, ex: [{ unless: ‘role’}, ‘role’, { if: { run_list: ‘role’, role: ‘pg_data’ } }]



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/cheftacular/parser.rb', line 134

def exclude_nodes nodes, statement_arr, only_one_node=false, ret_arr=[]
  nodes.each do |n|
    go_next = false

    statement_arr.each do |statement_hash|
      statement_hash.each_pair do |if_key, statement|
        if statement.is_a?(String)
          self.instance_eval("go_next = true #{ if_key.to_s } n.run_list.include?('#{ statement }')")

        elsif statement.is_a?(Hash)
          eval_string = "go_next = true #{ if_key.to_s } "
          eval_list = []

          statement.each_pair do |run_key, check_val|
            eval_list << "n.run_list.include?('#{ check_val }')"  if run_key == :run_list
            eval_list << "!n.run_list.include?('#{ check_val }')" if run_key == :not_run_list
            eval_list << "n.chef_environment == '#{ check_val }'" if run_key == :env
            eval_list << "n.chef_environment != '#{ check_val }'" if run_key == :not_env
            eval_list << "@options['role'] == '#{ check_val }'"   if run_key == :role
            eval_list << "@options['role'] != '#{ check_val }'"   if run_key == :not_role
            eval_list << "n.name == '#{ check_val }'"             if run_key == :node
            eval_list << "n.name != '#{ check_val }'"             if run_key == :not_node
            eval_list << "#{ check_val }"                         if run_key == :eval #careful with this, you need to pass in an already parsed string
          end

          self.instance_eval(eval_string + eval_list.join(' && '))
        else
          raise "Invalid statement type (#{ statement.class }) - Statement must be string or hash"
        end
      end
    end

    next if go_next

    ret_arr << n

    break if only_one_node
  end

  if @options['verbose'] && @options['command'] != "client_list" 
    puts("Parsed #{ ret_arr.count } nodes. Preparing to run on #{ ret_arr.map { |n| n.name }.join(',') } in env #{ @options['env'] } on role #{ @options['role'] }")
  end

  ret_arr
end

#index_of_node_name_in_array_of_nodes(nodes, node_name, names = []) ⇒ Object



127
128
129
130
131
# File 'lib/cheftacular/parser.rb', line 127

def index_of_node_name_in_array_of_nodes nodes, node_name, names=[]
  nodes.each { |node| names << node['name'] }

  names.index node_name
end

#parse_address(address) ⇒ Object



90
91
92
93
94
95
96
97
98
# File 'lib/cheftacular/parser.rb', line 90

def parse_address address
  addresses ||= []
  @config['chef_nodes'].each {|n| addresses << n.public_ipaddress }

  if address.nil?                   then raise "You attempted to specify an address but did not pass one, please use -a IP_ADDRESS"
  elsif addresses.include?(address) then @options['address'] = address
  else                                   raise "Unable to parse address: #{ address }, the address you're referring to is not part of any environment"
  end
end

#parse_and_set_deploy_argsObject



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cheftacular/parser.rb', line 100

def parse_and_set_deploy_args
  raise "Cannot set or unset target_revision without a role" unless @options['role']

  repo_state_hash   = @config[@options['env']]['config_bag_hash'][@options['sub_env']]['app_revisions'][@config['getter'].get_repository_from_role_name(@options['role'])]
  repo_state_hash ||= {}

  repo_state_hash['revision']            = @options['target_revision']     if @options['target_revision']
  repo_state_hash['deploy_organization'] = @options['deploy_organization'] if @options['deploy_organization']

  if @options['unset_github_deploy_args']
    repo_state_hash['revision']            = nil
    repo_state_hash['deploy_organization'] = nil
  end

  @config['helper'].check_if_possible_repo_state(repo_state_hash) if @config['cheftacular']['git']['check_remote_for_branch_existence'] && !@config['helper'].running_on_chef_node?

  @config['helper'].slack_current_deploy_arguments unless @config['cheftacular']['slack']['notify_on_deployment_args'].blank?

  @config['ChefDataBag'].save_config_bag 
end

#parse_application_contextObject

try and get the most accurate name of the repo



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/cheftacular/parser.rb', line 26

def parse_application_context
  working_dir = Dir.getwd.split('/').last

  #if there is no mapping setup for the directory, try and parse it from the .ruby-gemset file
  if File.exist?(File.expand_path("#{ @config['locs']['app-root'] }/.ruby-gemset")) && !@config['getter'].get_repository_from_role_name(working_dir, "has_value?")
    working_dir = File.read(File.expand_path("#{ @config['locs']['app-root'] }/.ruby-gemset")).chomp
  end

  if @config['getter'].get_repository_from_role_name(working_dir, "has_value?")
    @options['repository'] = working_dir unless @options['repository'] #enable custom -r or -R flags to get through in application directories

    parse_repository(@options['repository'])

    @options['command'] = ARGV[0] unless @config['helper'].is_not_command_or_stateless_command?(ARGV[0])
  end

  return if !@options['repository'].nil? && !@options['role'].nil? && !@options['command'].nil?
  return if !@options['command'].nil? && @config['helper'].is_stateless_command?(ARGV[0])
end

#parse_base_chef_server_urlObject



233
234
235
236
237
# File 'lib/cheftacular/parser.rb', line 233

def parse_base_chef_server_url
  domain = PublicSuffix.parse @config['cheftacular']['chef_server_url'].gsub('https://','').split('/').first

  "#{ domain.trd }.#{ domain.domain }"
end

#parse_contextObject

parses and validates the inputs from the initializer



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/cheftacular/parser.rb', line 9

def parse_context
  return if @config['repository'] && @config['command'] && @config['role']

  @options['command'] = ARGV[0] unless @options['command']

  parse_role(@options['role']) unless @options['role'].nil?

  parse_repository(@options['repository'])

  parse_node_name(@options['node_name']) if @options['node_name']

  parse_address(@options['address']) if @options['address']

  parse_and_set_deploy_args if @options['target_revision'] || @options['deploy_organization'] || @options['unset_github_deploy_args']
end

#parse_location_alias(string) ⇒ Object



208
209
210
211
212
213
214
215
216
# File 'lib/cheftacular/parser.rb', line 208

def parse_location_alias string
  if @config['cheftacular']['location_aliases'].keys.include?(string)
    puts("Matched location_alias #{ string } to #{ @config['cheftacular']['location_aliases'][string] }") unless @options['quiet']

    string = @config['cheftacular']['location_aliases'][string]
  end

  string
end

#parse_mode_into_command(mode) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/cheftacular/parser.rb', line 218

def parse_mode_into_command mode
  case mode.split(':').first
  when /display/ then 'cat'
  when 'edit'    then mode.split(':').last
  when 'tail'
    if mode.split(':').last == 'tail'
      'tail -500'
    else
      "tail -#{ mode.split(':').last }"
    end
  when 'tail-f'  then 'tail -f'
  else                mode
  end
end

#parse_node_name(name) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/cheftacular/parser.rb', line 80

def parse_node_name name
  nodes ||= []
  @config['chef_nodes'].each {|n| nodes << n.name }

  if name.nil?               then raise "You attempted to specify a node_name but did not pass one, please use -n NODE_NAME"
  elsif nodes.include?(name) then @options['node_name'] = name
  else                            raise "Unable to parse node_name: #{ name }, the node you're referring to does not exist."
  end
end

#parse_repo_state_hash_from_commit_hash(commit_hash, repo_state_hash = {'revision' => [], 'deploy_organization' => [], 'branch' => []}) ⇒ Object



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/cheftacular/parser.rb', line 239

def parse_repo_state_hash_from_commit_hash commit_hash, repo_state_hash={'revision' => [], 'deploy_organization' => [], 'branch' => []}
  commit_hash.each_value do |repo_hash|        
    repo_hash.each_value do |state_hash|
      next if state_hash.nil?

      repo_state_hash['revision']            << state_hash['name']
      repo_state_hash['branch']              << state_hash['branch']
      repo_state_hash['deploy_organization'] << state_hash['organization']
    end
  end

  repo_state_hash['revision']            = repo_state_hash['revision'].compact.uniq.first
  repo_state_hash['branch']              = repo_state_hash['branch'].compact.uniq.first
  repo_state_hash['deploy_organization'] = repo_state_hash['deploy_organization'].compact.uniq.first

  repo_state_hash
end

#parse_repository(repository, set_variables = true) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/cheftacular/parser.rb', line 46

def parse_repository repository, set_variables=true
  repo_check_array = []

  @config['cheftacular']['repositories'].each_value do |h|
    repo_check_array << h['repo_name'].include?(repository) unless repository.nil?
  end

  if repository.nil? && @config['helper'].running_in_mode?('devops')
    raise "Unable to parse a repository, please pass in the argument -c REPOSITORY to pass a repo"

  elsif repo_check_array.include?(true)
    @config['cheftacular']['repositories'].each_pair do |key, repo_hash|
      @options['role'] = key if repo_hash['repo_name'] == repository && set_variables && @options['role'].nil?
    end
  else
    raise "Unable to parse repository: #{ repository }, the repository you're referring to does not exist in your cheftacular.yml."
  end
end

#parse_repository_hash_from_string(string, checked_hashes = {}) ⇒ Object



200
201
202
203
204
205
206
# File 'lib/cheftacular/parser.rb', line 200

def parse_repository_hash_from_string string, checked_hashes={}
  @config['getter'].get_repo_names_for_repositories.each do |repository, repository_hash|
    checked_hashes[repository_hash['role']] = @config['helper'].compare_strings(string, repository)
  end

  return @config['cheftacular']['repositories'][ Hash[checked_hashes.sort_by { |key, val| val }].keys.first ]
end

#parse_role(role, mode = "set") ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/cheftacular/parser.rb', line 65

def parse_role role, mode="set"
  roles ||= []
  @config['chef_roles'].each {|r| roles << r.name }

  case mode
  when 'set'
    if role.nil?               then raise "Unable to parse a role, please pass in the argument -r ROLE_NAME to pass a role"
    elsif roles.include?(role) then @options['role'] = role
    else                            raise "Unable to parse role: #{ role }, #{ role } does not represent a valid role"
    end
  when 'boolean'
    roles.include?(role)
  end
end

#parse_runtime_arguments(num_of_args = 0, mode = 'normal') ⇒ Object



180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/cheftacular/parser.rb', line 180

def parse_runtime_arguments num_of_args=0, mode='normal'
  case mode
  when 'normal'
    case num_of_args
    when 0      then raise "You attempted to run #{ __method__ } with 0 args! Look up this method from the stacktrace!"
    when 1      then ARGV[num_of_args-1]
    when 2..100 then ARGV[0..(num_of_args-1)]
    end
  when 'range'  then ARGV[1..ARGV.length-1].join(' ')
  else  raise "You passed #{ mode }. This is not yet implemented for #{ __method__ }"
  end
end

#parse_to_dns(dns_string, node_name = '') ⇒ Object



193
194
195
196
197
198
# File 'lib/cheftacular/parser.rb', line 193

def parse_to_dns dns_string, node_name=''
  raise "Unable to parse DNS without node_name for #{ dns_string }!" if dns_string.include?('NODE_NAME') && node_name.blank?
  raise "Unable to parse DNS without a tld set in the config bag for #{ @options['env'] }!" if dns_string.include?('ENV_TLD') && @config[@options['env']]['config_bag_hash'][@options['sub_env']]['tld'].nil?

  dns_string.gsub('NODE_NAME', node_name).gsub('ENV_TLD', @config[@options['env']]['config_bag_hash'][@options['sub_env']]['tld'])
end