Skip to content

Commit

Permalink
Merge pull request #13584 from carbonin/ansible_inside
Browse files Browse the repository at this point in the history
Add methods for configuring and starting ansible inside
  • Loading branch information
jrafanie authored Jan 26, 2017
2 parents 3860236 + d277d40 commit b3ade89
Show file tree
Hide file tree
Showing 4 changed files with 428 additions and 7 deletions.
1 change: 1 addition & 0 deletions app/models/miq_database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class MiqDatabase < ApplicationRecord

include AuthenticationMixin
include PasswordMixin
include AnsibleAuthentications

virtual_has_many :vmdb_tables

Expand Down
83 changes: 83 additions & 0 deletions app/models/mixins/ansible_authentications.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
module AnsibleAuthentications
ANSIBLE_SECRET_KEY_TYPE = "ansible_secret_key".freeze
ANSIBLE_RABBITMQ_TYPE = "ansible_rabbitmq_auth".freeze
ANSIBLE_ADMIN_TYPE = "ansible_admin_password".freeze
ANSIBLE_DATABASE_TYPE = "ansible_database_password".freeze

AUTHENTICATION_CLASS_BY_TYPE = {
ANSIBLE_SECRET_KEY_TYPE => AuthToken,
ANSIBLE_RABBITMQ_TYPE => AuthUseridPassword,
ANSIBLE_ADMIN_TYPE => AuthUseridPassword,
ANSIBLE_DATABASE_TYPE => AuthUseridPassword
}.freeze

def self.included(base)
base.class_eval do
include AuthenticationMixin
end
end

def ansible_secret_key
auth = authentication_type(ANSIBLE_SECRET_KEY_TYPE)
auth.nil? ? nil : auth.auth_key
end

def ansible_secret_key=(key)
auth = authentication_for_type(ANSIBLE_SECRET_KEY_TYPE, "Ansible Secret Key")

auth.auth_key = key
auth.save!
end

def ansible_rabbitmq_password
auth = authentication_type(ANSIBLE_RABBITMQ_TYPE)
auth.nil? ? nil : auth.password
end

def ansible_rabbitmq_password=(password)
auth = authentication_for_type(ANSIBLE_RABBITMQ_TYPE, "Ansible Rabbitmq Password")

auth.userid = "tower"
auth.password = password
auth.save!
end

def ansible_admin_password
auth = authentication_type(ANSIBLE_ADMIN_TYPE)
auth.nil? ? nil : auth.password
end

def ansible_admin_password=(password)
auth = authentication_for_type(ANSIBLE_ADMIN_TYPE, "Ansible Admin Password")

auth.userid = "admin"
auth.password = password
auth.save!
end

def ansible_database_password
auth = authentication_type(ANSIBLE_DATABASE_TYPE)
auth.nil? ? nil : auth.password
end

def ansible_database_password=(password)
auth = authentication_for_type(ANSIBLE_DATABASE_TYPE, "Ansible Database Password")

auth.userid = "awx"
auth.password = password
auth.save!
end

private

def authentication_for_type(auth_type, name)
auth = authentication_type(auth_type)
return auth if auth

auth = AUTHENTICATION_CLASS_BY_TYPE[auth_type].new
auth.name = name
auth.resource = self
auth.authtype = auth_type
auth
end
end
147 changes: 140 additions & 7 deletions lib/embedded_ansible.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,156 @@
require "securerandom"
require "awesome_spawn"
require "linux_admin"

class EmbeddedAnsible
APPLIANCE_ANSIBLE_DIRECTORY = "/opt/ansible-installer".freeze
ANSIBLE_ROLE = "embedded_ansible".freeze
SETUP_SCRIPT = "#{APPLIANCE_ANSIBLE_DIRECTORY}/setup.sh".freeze
SECRET_KEY_FILE = "/etc/tower/SECRET_KEY".freeze
CONFIGURE_EXCLUDE_TAGS = "packages,migrations,firewall,supervisor".freeze
START_EXCLUDE_TAGS = "packages,migrations,firewall".freeze
NGINX_HTTP_PORT = "54321".freeze
NGINX_HTTPS_PORT = "54322".freeze

def self.available?
installed?
path = ENV["APPLIANCE_ANSIBLE_DIRECTORY"] || APPLIANCE_ANSIBLE_DIRECTORY
Dir.exist?(File.expand_path(path.to_s))
end

def self.enabled?
MiqServer.my_server(true).has_active_role?(ANSIBLE_ROLE)
end

def self.running?
# TODO
false
services.all? { |service| LinuxAdmin::Service.new(service).running? }
end

def self.installed?
path = ENV["APPLIANCE_ANSIBLE_DIRECTORY"] || APPLIANCE_ANSIBLE_DIRECTORY
Dir.exist?(File.expand_path(path.to_s))
def self.configured?
key = miq_database.ansible_secret_key
key.present? && key == File.read(SECRET_KEY_FILE)
end

def self.configure
configure_secret_key
run_setup_script(playbook_extra_variables.merge(:k => CONFIGURE_EXCLUDE_TAGS))
stop
end

def self.start
run_setup_script(playbook_extra_variables.merge(:k => START_EXCLUDE_TAGS))
end

def self.stop
services.each { |service| LinuxAdmin::Service.new(service).stop }
end

def self.disable
services.each { |service| LinuxAdmin::Service.new(service).stop.disable }
end

def self.services
AwesomeSpawn.run!("source /etc/sysconfig/ansible-tower; echo $TOWER_SERVICES").output.split
end

def self.playbook_extra_variables
json_value = {
:minimum_var_space => 0,
:nginx_http_port => NGINX_HTTP_PORT,
:nginx_https_port => NGINX_HTTPS_PORT
}.to_json
{:e => json_value}
end
private_class_method :playbook_extra_variables

def self.run_setup_script(params)
with_inventory_file do |inventory_file_path|
AwesomeSpawn.run!(SETUP_SCRIPT, :params => params.merge(:i => inventory_file_path))
end
end
private_class_method :run_setup_script

def self.with_inventory_file
file = Tempfile.new("miq_inventory")
begin
file.write(inventory_file_contents)
file.close
yield(file.path)
ensure
file.unlink
end
end
private_class_method :with_inventory_file

def self.configure_secret_key
key = miq_database.ansible_secret_key
if key.present?
File.write(SECRET_KEY_FILE, key)
else
AwesomeSpawn.run!("/usr/bin/python -c \"import uuid; file('#{SECRET_KEY_FILE}', 'wb').write(uuid.uuid4().hex)\"")
miq_database.ansible_secret_key = File.read(SECRET_KEY_FILE)
end
end
private_class_method :configure_secret_key

def self.generate_admin_password
miq_database.ansible_admin_password = generate_password
end
private_class_method :generate_admin_password

def self.generate_rabbitmq_password
miq_database.ansible_rabbitmq_password = generate_password
end
private_class_method :generate_rabbitmq_password

def self.generate_database_password
conn = ActiveRecord::Base.connection
password = generate_password
conn.select_value("CREATE ROLE awx WITH LOGIN PASSWORD #{conn.quote(password)}")
conn.select_value("CREATE DATABASE awx OWNER awx ENCODING 'utf8'")
miq_database.ansible_database_password = password
end
private_class_method :generate_database_password

def self.inventory_file_contents
admin_password = miq_database.ansible_admin_password || generate_admin_password
rabbitmq_password = miq_database.ansible_rabbitmq_password || generate_rabbitmq_password
database_password = miq_database.ansible_database_password || generate_database_password
db_config = Rails.configuration.database_configuration[Rails.env]

<<-EOF.strip_heredoc
[tower]
localhost ansible_connection=local
[database]
[all:vars]
admin_password='#{admin_password}'
pg_host='#{db_config["host"] || "localhost"}'
pg_port='#{db_config["port"] || "5432"}'
pg_database='awx'
pg_username='awx'
pg_password='#{database_password}'
rabbitmq_port=5672
rabbitmq_vhost=tower
rabbitmq_username=tower
rabbitmq_password='#{rabbitmq_password}'
rabbitmq_cookie=cookiemonster
rabbitmq_use_long_name=false
rabbitmq_enable_manager=false
EOF
end
private_class_method :inventory_file_contents

def self.miq_database
MiqDatabase.first
end
private_class_method :miq_database

def self.generate_password
SecureRandom.base64(18).tr("+/", "-_")
end
private_class_method :installed?
private_class_method :generate_password
end
Loading

0 comments on commit b3ade89

Please sign in to comment.