Class: Floaty

Inherits:
Object
  • Object
show all
Defined in:
lib/floatyhelper/floaty.rb

Constant Summary collapse

FLOATY_SERVICES =
{
  'abs' => {
    'type' => 'abs',
    'url' => 'https://abs-prod.k8s.infracore.puppet.net/api/v2',
  },
  'vmpooler' => {
    'type' => 'vm',
    'url' => 'http://vmpooler.delivery.puppetlabs.net',
  },
  'nspooler' => {
    'type' => 'nonstandard',
    'url' => 'https://nspooler-prod.k8s.infracore.puppet.net',
  },
}.freeze

Class Method Summary collapse

Class Method Details

.check_floaty(data = nil) ⇒ Object

This adds some stdout printing here which I was trying to avoid, but I think it makes sense to put it here rather than the main floatyhelper somewhere.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/floatyhelper/floaty.rb', line 38

def self.check_floaty(data = nil)
  data ||= load_vmfloaty_config

  user = data['user']
  unless user
    puts 'No username found in .vmfloaty.yml.'.yellow
    user = ask('Username: ').chomp
    data['user'] = user
  end
  data['services'] ||= {}
  puts 'No services defined in .vmfloaty.yml.' if data['services'].empty?

  need_token = FLOATY_SERVICES.keys.any? { |k| !data['services'].keys.include?(k) } || data['services'].any? { |_svc, val| val['token'].nil? }
  return unless need_token

  puts 'It appears we need to fetch one or more tokens for the ~/.vmfloaty.yml file. Please enter your Puppet password.'
  password = ask('Password: ') { |q| q.echo = '*' }
  FLOATY_SERVICES.each do |service, info|
    next if data['services'][service] && data['services'][service]['token']

    data['services'][service] ||= {}
    # Kind of silly to call out to curl here.  Replace this with a Net::HTTP call
    output, status = Open3.capture2e("curl -s -X POST -u #{user}:#{password} --url #{info['url']}/token")
    unless status.exitstatus.zero?
      puts "Bad return status from curl to #{info['url']}: #{status.exitstatus}".red
      exit status.exitstatus
    end
    result = JSON.parse(output)
    if result['ok']
      data['services'][service]['type'] = info['type']
      data['services'][service]['url'] = info['url']
      data['services'][service]['token'] = result['token']
      puts "Successfully fetched token for #{service}".green
    else
      puts "Could not get a token from #{service}. Please ensure your username and password are correct.".red
      puts "Result: #{result}".red
      exit 1
    end
  end
  File.write(vmfloatyfile, data.to_yaml)
end

.check_tokensObject

Make sure all tokens are valid



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/floatyhelper/floaty.rb', line 81

def self.check_tokens
  data = load_vmfloaty_config
  issues = false
  FLOATY_SERVICES.each do |service, info|
    if data['services'].nil? || data['services'][service].nil? || data['services'][service]['token'].nil?
      puts "#{service} service token not found in .vmfloaty.yml".yellow
      issues = true
      next
    end
    # TODO: See what exitcode is when token is bad vs. some other fatal error
    output, _status = Open3.capture2e("/usr/bin/env floaty token status --service #{service}")
    result = parse_floaty_json_output(output)
    next if result['ok']

    puts "Problem checking #{service} token: #{result['reason']}".red
    data['services'][service]['token'] = nil
    if result['reason'].include?('Unparseable')
      # User might have an old URL. Let's make sure to replace it with the latest.
      # Should probably actually check the output for a 503/404 rather than make the
      # assumption here.
      data['services'][service]['url'] = info['url']
    end
    issues = true
  end
  if issues
    check_floaty(data)
  else
    puts 'All tokens valid'.green
  end
end

.floaty_cmd(command, ignore_error: false, use_pty: false) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/floatyhelper/floaty.rb', line 122

def self.floaty_cmd(command, ignore_error: false, use_pty: false)
  check_floaty
  # While we could potentially make a Vmfloaty object and send a command
  # that way, Commander doesn't make it easy.  Parsing floaty's stdout
  # isn't great, but it works for now.
  if use_pty
    output = ''
    status = nil
    IO.popen("/usr/bin/env floaty #{command}", :err => [:child, :out]) do |io|
      while !Process.waitpid(io.pid, Process::WNOHANG)
        line = io.gets
        unless line.nil?
          puts line
          output += line
        end
      end
    end
    # Need to check exit status
    output
  else
    output, status = Open3.capture2e("/usr/bin/env floaty #{command}")
    if !status.exitstatus.zero? && !ignore_error
      puts "Error running 'floaty #{command}': #{output}".red
      exit status.exitstatus
    end
    output
  end
end

.load_vmfloaty_configObject



27
28
29
30
31
32
33
# File 'lib/floatyhelper/floaty.rb', line 27

def self.load_vmfloaty_config
  if File.exist?(vmfloatyfile)
    YAML.safe_load(File.read(vmfloatyfile))
  else
    {}
  end
end

.parse_floaty_json_output(output) ⇒ Object



112
113
114
115
116
117
118
119
120
# File 'lib/floatyhelper/floaty.rb', line 112

def self.parse_floaty_json_output(output)
  # Sometimes there will be extra stuff before the hash output,
  # so ignore it until we reach the hash.
  lines = output.split("\n")
  index = lines.index { |l| l[0] == '{' }
  return { 'ok' => false, 'reason' => 'Unparseable response from floaty' } if index.nil?
  output = lines[index..-1].join
  JSON.parse(output.gsub('=>',':'))
end

.vmfloatyfileObject



23
24
25
# File 'lib/floatyhelper/floaty.rb', line 23

def self.vmfloatyfile
  "#{Etc.getpwuid.dir}/.vmfloaty.yml"
end