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
# 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']['token'] = nil
    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



115
116
117
118
119
120
121
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
150
151
152
153
# File 'lib/floatyhelper/floaty.rb', line 115

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
    PTY.spawn("/usr/bin/env floaty #{command}") do |read, write, pid|
      write.close
      while status.nil?
        begin
          line = read.gets
          puts line
          output += line
        rescue EOFError, Errno::EIO
          # GNU/Linux raises EIO on read operation when pty is closed - see pty.rb docs
          # Ensure child process finishes and then pass through to ensure below to get status
          nil
        rescue IO::WaitReadable, IO::WaitWritable
          retry
        ensure
          status ||= PTY.check(pid)
        end
      end

      Process.waitall
      # Double check we have the status
      status ||= PTY.check(pid)
    end
  else
    output, status = Open3.capture2e("/usr/bin/env floaty #{command}")
  end
  if !status.exitstatus.zero? && !ignore_error
    puts "Error running 'floaty #{command}': #{output}".red
    exit status.exitstatus
  end
  output
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



106
107
108
109
110
111
112
113
# File 'lib/floatyhelper/floaty.rb', line 106

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] == '{' }
  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