Add certificate generation
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -112,3 +112,4 @@ roles/toallab.infrastructure/backup/
|
|||||||
roles/lightbulb-ansiblered-deck/
|
roles/lightbulb-ansiblered-deck/
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
keys/
|
||||||
|
|||||||
718
library/dnsmadeeasy.py
Normal file
718
library/dnsmadeeasy.py
Normal file
@@ -0,0 +1,718 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: dnsmadeeasy
|
||||||
|
version_added: "1.3"
|
||||||
|
short_description: Interface with dnsmadeeasy.com (a DNS hosting service).
|
||||||
|
description:
|
||||||
|
- >
|
||||||
|
Manages DNS records via the v2 REST API of the DNS Made Easy service. It handles records only; there is no manipulation of domains or
|
||||||
|
monitor/account support yet. See: U(https://www.dnsmadeeasy.com/integration/restapi/)
|
||||||
|
options:
|
||||||
|
account_key:
|
||||||
|
description:
|
||||||
|
- Account API Key.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
account_secret:
|
||||||
|
description:
|
||||||
|
- Account Secret Key.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
domain:
|
||||||
|
description:
|
||||||
|
- Domain to work with. Can be the domain name (e.g. "mydomain.com") or the numeric ID of the domain in DNS Made Easy (e.g. "839989") for faster
|
||||||
|
resolution
|
||||||
|
required: true
|
||||||
|
|
||||||
|
sandbox:
|
||||||
|
description:
|
||||||
|
- Decides if the sandbox API should be used. Otherwise (default) the production API of DNS Made Easy is used.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
version_added: 2.7
|
||||||
|
|
||||||
|
record_name:
|
||||||
|
description:
|
||||||
|
- Record name to get/create/delete/update. If record_name is not specified; all records for the domain will be returned in "result" regardless
|
||||||
|
of the state argument.
|
||||||
|
|
||||||
|
record_type:
|
||||||
|
description:
|
||||||
|
- Record type.
|
||||||
|
choices: [ 'A', 'AAAA', 'CNAME', 'ANAME', 'HTTPRED', 'MX', 'NS', 'PTR', 'SRV', 'TXT' ]
|
||||||
|
|
||||||
|
record_value:
|
||||||
|
description:
|
||||||
|
- >
|
||||||
|
Record value. HTTPRED: <redirection URL>, MX: <priority> <target name>, NS: <name server>, PTR: <target name>,
|
||||||
|
SRV: <priority> <weight> <port> <target name>, TXT: <text value>"
|
||||||
|
- >
|
||||||
|
If record_value is not specified; no changes will be made and the record will be returned in 'result'
|
||||||
|
(in other words, this module can be used to fetch a record's current id, type, and ttl)
|
||||||
|
|
||||||
|
record_ttl:
|
||||||
|
description:
|
||||||
|
- record's "Time to live". Number of seconds the record remains cached in DNS servers.
|
||||||
|
default: 1800
|
||||||
|
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- whether the record should exist or not
|
||||||
|
required: true
|
||||||
|
choices: [ 'present', 'absent' ]
|
||||||
|
|
||||||
|
validate_certs:
|
||||||
|
description:
|
||||||
|
- If C(no), SSL certificates will not be validated. This should only be used
|
||||||
|
on personally controlled sites using self-signed certificates.
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
version_added: 1.5.1
|
||||||
|
|
||||||
|
monitor:
|
||||||
|
description:
|
||||||
|
- If C(yes), add or change the monitor. This is applicable only for A records.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
systemDescription:
|
||||||
|
description:
|
||||||
|
- Description used by the monitor.
|
||||||
|
required: true
|
||||||
|
default: ''
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
maxEmails:
|
||||||
|
description:
|
||||||
|
- Number of emails sent to the contact list by the monitor.
|
||||||
|
required: true
|
||||||
|
default: 1
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
protocol:
|
||||||
|
description:
|
||||||
|
- Protocol used by the monitor.
|
||||||
|
required: true
|
||||||
|
default: 'HTTP'
|
||||||
|
choices: ['TCP', 'UDP', 'HTTP', 'DNS', 'SMTP', 'HTTPS']
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
port:
|
||||||
|
description:
|
||||||
|
- Port used by the monitor.
|
||||||
|
required: true
|
||||||
|
default: 80
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
sensitivity:
|
||||||
|
description:
|
||||||
|
- Number of checks the monitor performs before a failover occurs where Low = 8, Medium = 5,and High = 3.
|
||||||
|
required: true
|
||||||
|
default: 'Medium'
|
||||||
|
choices: ['Low', 'Medium', 'High']
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
contactList:
|
||||||
|
description:
|
||||||
|
- Name or id of the contact list that the monitor will notify.
|
||||||
|
- The default C('') means the Account Owner.
|
||||||
|
required: true
|
||||||
|
default: ''
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
httpFqdn:
|
||||||
|
description:
|
||||||
|
- The fully qualified domain name used by the monitor.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
httpFile:
|
||||||
|
description:
|
||||||
|
- The file at the Fqdn that the monitor queries for HTTP or HTTPS.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
httpQueryString:
|
||||||
|
description:
|
||||||
|
- The string in the httpFile that the monitor queries for HTTP or HTTPS.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
failover:
|
||||||
|
description:
|
||||||
|
- If C(yes), add or change the failover. This is applicable only for A records.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
autoFailover:
|
||||||
|
description:
|
||||||
|
- If true, fallback to the primary IP address is manual after a failover.
|
||||||
|
- If false, fallback to the primary IP address is automatic after a failover.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
ip1:
|
||||||
|
description:
|
||||||
|
- Primary IP address for the failover.
|
||||||
|
- Required if adding or changing the monitor or failover.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
ip2:
|
||||||
|
description:
|
||||||
|
- Secondary IP address for the failover.
|
||||||
|
- Required if adding or changing the failover.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
ip3:
|
||||||
|
description:
|
||||||
|
- Tertiary IP address for the failover.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
ip4:
|
||||||
|
description:
|
||||||
|
- Quaternary IP address for the failover.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
ip5:
|
||||||
|
description:
|
||||||
|
- Quinary IP address for the failover.
|
||||||
|
version_added: 2.4
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- The DNS Made Easy service requires that machines interacting with the API have the proper time and timezone set. Be sure you are within a few
|
||||||
|
seconds of actual time by using NTP.
|
||||||
|
- This module returns record(s) and monitor(s) in the "result" element when 'state' is set to 'present'.
|
||||||
|
These values can be be registered and used in your playbooks.
|
||||||
|
- Only A records can have a monitor or failover.
|
||||||
|
- To add failover, the 'failover', 'autoFailover', 'port', 'protocol', 'ip1', and 'ip2' options are required.
|
||||||
|
- To add monitor, the 'monitor', 'port', 'protocol', 'maxEmails', 'systemDescription', and 'ip1' options are required.
|
||||||
|
- The monitor and the failover will share 'port', 'protocol', and 'ip1' options.
|
||||||
|
|
||||||
|
requirements: [ hashlib, hmac ]
|
||||||
|
author: "Brice Burgess (@briceburg)"
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# fetch my.com domain records
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
register: response
|
||||||
|
|
||||||
|
# create / ensure the presence of a record
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
|
||||||
|
# update the previously created record
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_value: 192.0.2.23
|
||||||
|
|
||||||
|
# fetch a specific record
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
register: response
|
||||||
|
|
||||||
|
# delete a record / ensure it is absent
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
record_type: A
|
||||||
|
state: absent
|
||||||
|
record_name: test
|
||||||
|
|
||||||
|
# Add a failover
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
failover: True
|
||||||
|
ip1: 127.0.0.2
|
||||||
|
ip2: 127.0.0.3
|
||||||
|
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
failover: True
|
||||||
|
ip1: 127.0.0.2
|
||||||
|
ip2: 127.0.0.3
|
||||||
|
ip3: 127.0.0.4
|
||||||
|
ip4: 127.0.0.5
|
||||||
|
ip5: 127.0.0.6
|
||||||
|
|
||||||
|
# Add a monitor
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
monitor: yes
|
||||||
|
ip1: 127.0.0.2
|
||||||
|
protocol: HTTP # default
|
||||||
|
port: 80 # default
|
||||||
|
maxEmails: 1
|
||||||
|
systemDescription: Monitor Test A record
|
||||||
|
contactList: my contact list
|
||||||
|
|
||||||
|
# Add a monitor with http options
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
monitor: yes
|
||||||
|
ip1: 127.0.0.2
|
||||||
|
protocol: HTTP # default
|
||||||
|
port: 80 # default
|
||||||
|
maxEmails: 1
|
||||||
|
systemDescription: Monitor Test A record
|
||||||
|
contactList: 1174 # contact list id
|
||||||
|
httpFqdn: http://my.com
|
||||||
|
httpFile: example
|
||||||
|
httpQueryString: some string
|
||||||
|
|
||||||
|
# Add a monitor and a failover
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
failover: True
|
||||||
|
ip1: 127.0.0.2
|
||||||
|
ip2: 127.0.0.3
|
||||||
|
monitor: yes
|
||||||
|
protocol: HTTPS
|
||||||
|
port: 443
|
||||||
|
maxEmails: 1
|
||||||
|
systemDescription: monitoring my.com status
|
||||||
|
contactList: emergencycontacts
|
||||||
|
|
||||||
|
# Remove a failover
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
failover: no
|
||||||
|
|
||||||
|
# Remove a monitor
|
||||||
|
- dnsmadeeasy:
|
||||||
|
account_key: key
|
||||||
|
account_secret: secret
|
||||||
|
domain: my.com
|
||||||
|
state: present
|
||||||
|
record_name: test
|
||||||
|
record_type: A
|
||||||
|
record_value: 127.0.0.1
|
||||||
|
monitor: no
|
||||||
|
'''
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# DNSMadeEasy module specific support methods.
|
||||||
|
#
|
||||||
|
|
||||||
|
import json
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
from time import strftime, gmtime
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.urls import fetch_url
|
||||||
|
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||||
|
from ansible.module_utils.six import string_types
|
||||||
|
|
||||||
|
|
||||||
|
class DME2(object):
|
||||||
|
|
||||||
|
def __init__(self, apikey, secret, domain, sandbox, module):
|
||||||
|
self.module = module
|
||||||
|
|
||||||
|
self.api = apikey
|
||||||
|
self.secret = secret
|
||||||
|
|
||||||
|
if sandbox:
|
||||||
|
self.baseurl = 'https://api.sandbox.dnsmadeeasy.com/V2.0/'
|
||||||
|
self.module.warn(warning="Sandbox is enabled. All actions are made against the URL %s" % self.baseurl)
|
||||||
|
else:
|
||||||
|
self.baseurl = 'https://api.dnsmadeeasy.com/V2.0/'
|
||||||
|
|
||||||
|
self.domain = str(domain)
|
||||||
|
self.domain_map = None # ["domain_name"] => ID
|
||||||
|
self.record_map = None # ["record_name"] => ID
|
||||||
|
self.records = None # ["record_ID"] => <record>
|
||||||
|
self.all_records = None
|
||||||
|
self.contactList_map = None # ["contactList_name"] => ID
|
||||||
|
|
||||||
|
# Lookup the domain ID if passed as a domain name vs. ID
|
||||||
|
if not self.domain.isdigit():
|
||||||
|
self.domain = self.getDomainByName(self.domain)['id']
|
||||||
|
|
||||||
|
self.record_url = 'dns/managed/' + str(self.domain) + '/records'
|
||||||
|
self.monitor_url = 'monitor'
|
||||||
|
self.contactList_url = 'contactList'
|
||||||
|
|
||||||
|
def _headers(self):
|
||||||
|
currTime = self._get_date()
|
||||||
|
hashstring = self._create_hash(currTime)
|
||||||
|
headers = {'x-dnsme-apiKey': self.api,
|
||||||
|
'x-dnsme-hmac': hashstring,
|
||||||
|
'x-dnsme-requestDate': currTime,
|
||||||
|
'content-type': 'application/json'}
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def _get_date(self):
|
||||||
|
return strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime())
|
||||||
|
|
||||||
|
def _create_hash(self, rightnow):
|
||||||
|
return hmac.new(self.secret.encode(), rightnow.encode(), hashlib.sha1).hexdigest()
|
||||||
|
|
||||||
|
def query(self, resource, method, data=None):
|
||||||
|
url = self.baseurl + resource
|
||||||
|
if data and not isinstance(data, string_types):
|
||||||
|
data = urlencode(data)
|
||||||
|
|
||||||
|
response, info = fetch_url(self.module, url, data=data, method=method, headers=self._headers())
|
||||||
|
if info['status'] not in (200, 201, 204):
|
||||||
|
self.module.fail_json(msg="%s returned %s, with body: %s" % (url, info['status'], info['msg']))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return json.load(response)
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def getDomain(self, domain_id):
|
||||||
|
if not self.domain_map:
|
||||||
|
self._instMap('domain')
|
||||||
|
|
||||||
|
return self.domains.get(domain_id, False)
|
||||||
|
|
||||||
|
def getDomainByName(self, domain_name):
|
||||||
|
if not self.domain_map:
|
||||||
|
self._instMap('domain')
|
||||||
|
|
||||||
|
return self.getDomain(self.domain_map.get(domain_name, 0))
|
||||||
|
|
||||||
|
def getDomains(self):
|
||||||
|
return self.query('dns/managed', 'GET')['data']
|
||||||
|
|
||||||
|
def getRecord(self, record_id):
|
||||||
|
if not self.record_map:
|
||||||
|
self._instMap('record')
|
||||||
|
|
||||||
|
return self.records.get(record_id, False)
|
||||||
|
|
||||||
|
# Try to find a single record matching this one.
|
||||||
|
# How we do this depends on the type of record. For instance, there
|
||||||
|
# can be several MX records for a single record_name while there can
|
||||||
|
# only be a single CNAME for a particular record_name. Note also that
|
||||||
|
# there can be several records with different types for a single name.
|
||||||
|
def getMatchingRecord(self, record_name, record_type, record_value):
|
||||||
|
# Get all the records if not already cached
|
||||||
|
if not self.all_records:
|
||||||
|
self.all_records = self.getRecords()
|
||||||
|
|
||||||
|
if record_type in ["CNAME", "ANAME", "HTTPRED", "PTR"]:
|
||||||
|
for result in self.all_records:
|
||||||
|
if result['name'] == record_name and result['type'] == record_type:
|
||||||
|
return result
|
||||||
|
return False
|
||||||
|
elif record_type in ["A", "AAAA", "MX", "NS", "TXT", "SRV"]:
|
||||||
|
for result in self.all_records:
|
||||||
|
if record_type == "MX":
|
||||||
|
value = record_value.split(" ")[1]
|
||||||
|
elif record_type == "SRV":
|
||||||
|
value = record_value.split(" ")[3]
|
||||||
|
else:
|
||||||
|
value = record_value
|
||||||
|
if result['name'] == record_name and result['type'] == record_type and result['value'] == value:
|
||||||
|
return result
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise Exception('record_type not yet supported')
|
||||||
|
|
||||||
|
def getRecords(self):
|
||||||
|
return self.query(self.record_url, 'GET')['data']
|
||||||
|
|
||||||
|
def _instMap(self, type):
|
||||||
|
# @TODO cache this call so it's executed only once per ansible execution
|
||||||
|
map = {}
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
# iterate over e.g. self.getDomains() || self.getRecords()
|
||||||
|
for result in getattr(self, 'get' + type.title() + 's')():
|
||||||
|
|
||||||
|
map[result['name']] = result['id']
|
||||||
|
results[result['id']] = result
|
||||||
|
|
||||||
|
# e.g. self.domain_map || self.record_map
|
||||||
|
setattr(self, type + '_map', map)
|
||||||
|
setattr(self, type + 's', results) # e.g. self.domains || self.records
|
||||||
|
|
||||||
|
def prepareRecord(self, data):
|
||||||
|
return json.dumps(data, separators=(',', ':'))
|
||||||
|
|
||||||
|
def createRecord(self, data):
|
||||||
|
# @TODO update the cache w/ resultant record + id when impleneted
|
||||||
|
return self.query(self.record_url, 'POST', data)
|
||||||
|
|
||||||
|
def updateRecord(self, record_id, data):
|
||||||
|
# @TODO update the cache w/ resultant record + id when impleneted
|
||||||
|
return self.query(self.record_url + '/' + str(record_id), 'PUT', data)
|
||||||
|
|
||||||
|
def deleteRecord(self, record_id):
|
||||||
|
# @TODO remove record from the cache when impleneted
|
||||||
|
return self.query(self.record_url + '/' + str(record_id), 'DELETE')
|
||||||
|
|
||||||
|
def getMonitor(self, record_id):
|
||||||
|
return self.query(self.monitor_url + '/' + str(record_id), 'GET')
|
||||||
|
|
||||||
|
def updateMonitor(self, record_id, data):
|
||||||
|
return self.query(self.monitor_url + '/' + str(record_id), 'PUT', data)
|
||||||
|
|
||||||
|
def prepareMonitor(self, data):
|
||||||
|
return json.dumps(data, separators=(',', ':'))
|
||||||
|
|
||||||
|
def getContactList(self, contact_list_id):
|
||||||
|
if not self.contactList_map:
|
||||||
|
self._instMap('contactList')
|
||||||
|
|
||||||
|
return self.contactLists.get(contact_list_id, False)
|
||||||
|
|
||||||
|
def getContactlists(self):
|
||||||
|
return self.query(self.contactList_url, 'GET')['data']
|
||||||
|
|
||||||
|
def getContactListByName(self, name):
|
||||||
|
if not self.contactList_map:
|
||||||
|
self._instMap('contactList')
|
||||||
|
|
||||||
|
return self.getContactList(self.contactList_map.get(name, 0))
|
||||||
|
|
||||||
|
# ===========================================
|
||||||
|
# Module execution.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
account_key=dict(required=True),
|
||||||
|
account_secret=dict(required=True, no_log=True),
|
||||||
|
domain=dict(required=True),
|
||||||
|
sandbox=dict(default='no', type='bool'),
|
||||||
|
state=dict(required=True, choices=['present', 'absent']),
|
||||||
|
record_name=dict(required=False),
|
||||||
|
record_type=dict(required=False, choices=[
|
||||||
|
'A', 'AAAA', 'CNAME', 'ANAME', 'HTTPRED', 'MX', 'NS', 'PTR', 'SRV', 'TXT']),
|
||||||
|
record_value=dict(required=False),
|
||||||
|
record_ttl=dict(required=False, default=1800, type='int'),
|
||||||
|
monitor=dict(default='no', type='bool'),
|
||||||
|
systemDescription=dict(default=''),
|
||||||
|
maxEmails=dict(default=1, type='int'),
|
||||||
|
protocol=dict(default='HTTP', choices=['TCP', 'UDP', 'HTTP', 'DNS', 'SMTP', 'HTTPS']),
|
||||||
|
port=dict(default=80, type='int'),
|
||||||
|
sensitivity=dict(default='Medium', choices=['Low', 'Medium', 'High']),
|
||||||
|
contactList=dict(default=None),
|
||||||
|
httpFqdn=dict(required=False),
|
||||||
|
httpFile=dict(required=False),
|
||||||
|
httpQueryString=dict(required=False),
|
||||||
|
failover=dict(default='no', type='bool'),
|
||||||
|
autoFailover=dict(default='no', type='bool'),
|
||||||
|
ip1=dict(required=False),
|
||||||
|
ip2=dict(required=False),
|
||||||
|
ip3=dict(required=False),
|
||||||
|
ip4=dict(required=False),
|
||||||
|
ip5=dict(required=False),
|
||||||
|
validate_certs=dict(default='yes', type='bool'),
|
||||||
|
),
|
||||||
|
required_together=[
|
||||||
|
['record_value', 'record_ttl', 'record_type']
|
||||||
|
],
|
||||||
|
required_if=[
|
||||||
|
['failover', True, ['autoFailover', 'port', 'protocol', 'ip1', 'ip2']],
|
||||||
|
['monitor', True, ['port', 'protocol', 'maxEmails', 'systemDescription', 'ip1']]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
protocols = dict(TCP=1, UDP=2, HTTP=3, DNS=4, SMTP=5, HTTPS=6)
|
||||||
|
sensitivities = dict(Low=8, Medium=5, High=3)
|
||||||
|
|
||||||
|
DME = DME2(module.params["account_key"], module.params[
|
||||||
|
"account_secret"], module.params["domain"], module.params["sandbox"], module)
|
||||||
|
state = module.params["state"]
|
||||||
|
record_name = module.params["record_name"]
|
||||||
|
record_type = module.params["record_type"]
|
||||||
|
record_value = module.params["record_value"]
|
||||||
|
|
||||||
|
# Follow Keyword Controlled Behavior
|
||||||
|
if record_name is None:
|
||||||
|
domain_records = DME.getRecords()
|
||||||
|
if not domain_records:
|
||||||
|
module.fail_json(
|
||||||
|
msg="The requested domain name is not accessible with this api_key; try using its ID if known.")
|
||||||
|
module.exit_json(changed=False, result=domain_records)
|
||||||
|
|
||||||
|
# Fetch existing record + Build new one
|
||||||
|
current_record = DME.getMatchingRecord(record_name, record_type, record_value)
|
||||||
|
new_record = {'name': record_name}
|
||||||
|
for i in ["record_value", "record_type", "record_ttl"]:
|
||||||
|
if not module.params[i] is None:
|
||||||
|
new_record[i[len("record_"):]] = module.params[i]
|
||||||
|
# Special handling for mx record
|
||||||
|
if new_record["type"] == "MX":
|
||||||
|
new_record["mxLevel"] = new_record["value"].split(" ")[0]
|
||||||
|
new_record["value"] = new_record["value"].split(" ")[1]
|
||||||
|
|
||||||
|
# Special handling for SRV records
|
||||||
|
if new_record["type"] == "SRV":
|
||||||
|
new_record["priority"] = new_record["value"].split(" ")[0]
|
||||||
|
new_record["weight"] = new_record["value"].split(" ")[1]
|
||||||
|
new_record["port"] = new_record["value"].split(" ")[2]
|
||||||
|
new_record["value"] = new_record["value"].split(" ")[3]
|
||||||
|
|
||||||
|
# Fetch existing monitor if the A record indicates it should exist and build the new monitor
|
||||||
|
current_monitor = dict()
|
||||||
|
new_monitor = dict()
|
||||||
|
if current_record and current_record['type'] == 'A':
|
||||||
|
current_monitor = DME.getMonitor(current_record['id'])
|
||||||
|
|
||||||
|
# Build the new monitor
|
||||||
|
for i in ['monitor', 'systemDescription', 'protocol', 'port', 'sensitivity', 'maxEmails',
|
||||||
|
'contactList', 'httpFqdn', 'httpFile', 'httpQueryString',
|
||||||
|
'failover', 'autoFailover', 'ip1', 'ip2', 'ip3', 'ip4', 'ip5']:
|
||||||
|
if module.params[i] is not None:
|
||||||
|
if i == 'protocol':
|
||||||
|
# The API requires protocol to be a numeric in the range 1-6
|
||||||
|
new_monitor['protocolId'] = protocols[module.params[i]]
|
||||||
|
elif i == 'sensitivity':
|
||||||
|
# The API requires sensitivity to be a numeric of 8, 5, or 3
|
||||||
|
new_monitor[i] = sensitivities[module.params[i]]
|
||||||
|
elif i == 'contactList':
|
||||||
|
# The module accepts either the name or the id of the contact list
|
||||||
|
contact_list_id = module.params[i]
|
||||||
|
if not contact_list_id.isdigit() and contact_list_id != '':
|
||||||
|
contact_list = DME.getContactListByName(contact_list_id)
|
||||||
|
if not contact_list:
|
||||||
|
module.fail_json(msg="Contact list {0} does not exist".format(contact_list_id))
|
||||||
|
contact_list_id = contact_list.get('id', '')
|
||||||
|
new_monitor['contactListId'] = contact_list_id
|
||||||
|
else:
|
||||||
|
# The module option names match the API field names
|
||||||
|
new_monitor[i] = module.params[i]
|
||||||
|
|
||||||
|
# Compare new record against existing one
|
||||||
|
record_changed = False
|
||||||
|
if current_record:
|
||||||
|
for i in new_record:
|
||||||
|
if str(current_record[i]) != str(new_record[i]):
|
||||||
|
record_changed = True
|
||||||
|
new_record['id'] = str(current_record['id'])
|
||||||
|
|
||||||
|
monitor_changed = False
|
||||||
|
if current_monitor:
|
||||||
|
for i in new_monitor:
|
||||||
|
if str(current_monitor.get(i)) != str(new_monitor[i]):
|
||||||
|
monitor_changed = True
|
||||||
|
|
||||||
|
# Follow Keyword Controlled Behavior
|
||||||
|
if state == 'present':
|
||||||
|
# return the record if no value is specified
|
||||||
|
if "value" not in new_record:
|
||||||
|
if not current_record:
|
||||||
|
module.fail_json(
|
||||||
|
msg="A record with name '%s' does not exist for domain '%s.'" % (record_name, module.params['domain']))
|
||||||
|
module.exit_json(changed=False, result=dict(record=current_record, monitor=current_monitor))
|
||||||
|
|
||||||
|
# create record and monitor as the record does not exist
|
||||||
|
if not current_record:
|
||||||
|
record = DME.createRecord(DME.prepareRecord(new_record))
|
||||||
|
if module.params['monitor']:
|
||||||
|
monitor = DME.updateMonitor(record['id'], DME.prepareMonitor(new_monitor))
|
||||||
|
module.exit_json(changed=True, result=dict(record=record, monitor=monitor))
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=True, result=dict(record=record))
|
||||||
|
|
||||||
|
# update the record
|
||||||
|
updated = False
|
||||||
|
if record_changed:
|
||||||
|
DME.updateRecord(current_record['id'], DME.prepareRecord(new_record))
|
||||||
|
updated = True
|
||||||
|
if monitor_changed:
|
||||||
|
DME.updateMonitor(current_monitor['recordId'], DME.prepareMonitor(new_monitor))
|
||||||
|
updated = True
|
||||||
|
if updated:
|
||||||
|
module.exit_json(changed=True, result=dict(record=new_record, monitor=new_monitor))
|
||||||
|
|
||||||
|
# return the record (no changes)
|
||||||
|
module.exit_json(changed=False, result=dict(record=current_record, monitor=current_monitor))
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
changed = False
|
||||||
|
# delete the record (and the monitor/failover) if it exists
|
||||||
|
if current_record:
|
||||||
|
DME.deleteRecord(current_record['id'])
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
|
||||||
|
# record does not exist, return w/o change.
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
else:
|
||||||
|
module.fail_json(
|
||||||
|
msg="'%s' is an unknown value for the state argument" % state)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,6 +1,41 @@
|
|||||||
---
|
---
|
||||||
|
# Probably want to split this out into a proper certificate management role for Toal.ca
|
||||||
|
- name: Request TLS Certificate from LetsEncrypt
|
||||||
|
hosts: rhv.mgmt.toal.ca
|
||||||
|
connection: local
|
||||||
|
gather_facts: false
|
||||||
|
# This doesn't belong here
|
||||||
|
vars:
|
||||||
|
acme_email: ptoal@takeflight.ca
|
||||||
|
challenge: dns-01
|
||||||
|
dns_provider: dme
|
||||||
|
domains:
|
||||||
|
- rhv.mgmt.toal.ca
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- name: Ensure Let's Encrypt Account Exists
|
||||||
|
acme_account:
|
||||||
|
state: present
|
||||||
|
terms_agreed: true
|
||||||
|
allow_creation: true
|
||||||
|
contact:
|
||||||
|
- mailto:ptoal@takeflight.ca
|
||||||
|
account_key_content: "{{ acme_key }}"
|
||||||
|
acme_version: 2
|
||||||
|
roles:
|
||||||
|
- acme-certificate
|
||||||
|
|
||||||
|
|
||||||
|
# - name: Install custom CA Certificate in RHV-M
|
||||||
|
# hosts: rhv.lab.toal.ca
|
||||||
|
|
||||||
|
# tasks:
|
||||||
|
# - name: Download LetsEncrypt Root/Intermediate Certificates
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Create RHV/ovirt VLANs
|
- name: Create RHV/ovirt VLANs
|
||||||
hosts: rhv.lab.toal.ca
|
hosts: rhv.mgmt.toal.ca
|
||||||
connection: local
|
connection: local
|
||||||
vars:
|
vars:
|
||||||
# Hack to work around virtualenv python interpreter
|
# Hack to work around virtualenv python interpreter
|
||||||
@@ -11,7 +46,7 @@
|
|||||||
fetch_nested: true
|
fetch_nested: true
|
||||||
data_center: "{{ item.data_center }}"
|
data_center: "{{ item.data_center }}"
|
||||||
name: "{{ item.name }}"
|
name: "{{ item.name }}"
|
||||||
vlan_tag: "{{ item.vlan_tag }}"
|
vlan_tag: "{{ item.vlan_tag|default(omit) }}"
|
||||||
vm_network: "{{ item.vm_network }}"
|
vm_network: "{{ item.vm_network }}"
|
||||||
mtu: "{{ item.mtu }}"
|
mtu: "{{ item.mtu }}"
|
||||||
description: "{{ item.description }}"
|
description: "{{ item.description }}"
|
||||||
|
|||||||
1
roles/acme-certificate
Symbolic link
1
roles/acme-certificate
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/Users/ptoal/Dev/acme-certificate/
|
||||||
6
roles/ovirt.manageiq/.gitignore
vendored
Normal file
6
roles/ovirt.manageiq/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
*retry
|
||||||
|
.tox
|
||||||
|
*.tar.gz
|
||||||
|
output/
|
||||||
|
ovirt-ansible-manageiq.spec
|
||||||
|
exported-artifacts/
|
||||||
31
roles/ovirt.manageiq/.travis.yml
Normal file
31
roles/ovirt.manageiq/.travis.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
sudo: required
|
||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- "2.7"
|
||||||
|
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- ANSIBLE_HOST_KEY_CHECKING="False"
|
||||||
|
|
||||||
|
# Install python-pip
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- python-pip
|
||||||
|
|
||||||
|
install:
|
||||||
|
- pip install tox ansible docker-py yamllint
|
||||||
|
|
||||||
|
# Check ansible version
|
||||||
|
- ansible --version
|
||||||
|
|
||||||
|
script:
|
||||||
|
# Run sytax checks and linters
|
||||||
|
- tox
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
webhooks: https://galaxy.ansible.com/api/v1/notifications/
|
||||||
191
roles/ovirt.manageiq/LICENSE
Normal file
191
roles/ovirt.manageiq/LICENSE
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Copyright 2014 Red Hat, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
264
roles/ovirt.manageiq/README.md
Normal file
264
roles/ovirt.manageiq/README.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
Deploy ManageIQ in oVirt
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
The `ovirt.manageiq` role downloads a ManageIQ/CloudForms QCOW image and deploys it into oVirt/Red Hat Virtualization (RHV).
|
||||||
|
|
||||||
|
The role also enables you to create a virtual machine and attach the ManageIQ disk, then wait for the ManageIQ system to initialize, and register oVirt as an infrastructure provider.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
Please note that when installing this role from Ansible Galaxy you are instructed to run following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ansible-galaxy install ovirt.manageiq
|
||||||
|
```
|
||||||
|
|
||||||
|
This will download the role to the directory with the same name as you specified on the
|
||||||
|
command line, in this case `ovirt.manageiq`. But note that it is case sensitive, so if you specify
|
||||||
|
for example `OVIRT.manageiq` it will download the same role, but it will add it to the directory named
|
||||||
|
`OVIRT.manageiq`, so you later always have to use this role with upper case prefix. So be careful how
|
||||||
|
you specify the name of the role on command line.
|
||||||
|
|
||||||
|
For the RPM installation we install three legacy names `oVirt.manageiq`, `ovirt.manageiq` and `ovirt-manageiq`.
|
||||||
|
So you can use any of these names. This documentation and examples in this repository are using name `ovirt.manageiq`.
|
||||||
|
`oVirt.manageiq` and `ovirt-manageiq` role names are deprecated.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
* oVirt has to be 4.0.4 or higher.
|
||||||
|
* Ansible has to be 2.5 or higher.
|
||||||
|
* [ovirt-imageio](http://www.ovirt.org/develop/release-management/features/storage/image-upload/) must be installed and running.
|
||||||
|
* [oVirt Python SDK version 4](https://pypi.python.org/pypi/ovirt-engine-sdk-python/4.2.4).
|
||||||
|
|
||||||
|
Additionally, perform the following checks to ensure the required processes are running.
|
||||||
|
* Check whether `ovirt-imageio-proxy` is running on the engine:
|
||||||
|
|
||||||
|
```
|
||||||
|
systemctl status ovirt-imageio-proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
* Check whether `ovirt-imageio-daemon` is running on the hosts:
|
||||||
|
|
||||||
|
```
|
||||||
|
systemctl status ovirt-imageio-daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
You will also require the CA certificate of the engine. To do this, configure the `ovirt_ca` variable with the path to the CA certificate.
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* We don not support Ansible Check Mode (Dry Run), because this role is using few modules(command module),
|
||||||
|
which do not support it. Once all modules used by this role will support it, we will support it.
|
||||||
|
|
||||||
|
Role Variables
|
||||||
|
--------------
|
||||||
|
|
||||||
|
QCOW variables:
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|---------------|----------------------------------------------------------|--------------------------------------------------------------|
|
||||||
|
| miq_qcow_url | http://releases.manageiq.org/manageiq-ovirt-gaprindashvili-3.qc2 | The URL of the ManageIQ QCOW image. |
|
||||||
|
| miq_image_path | /tmp/ | Path where the QCOW2 image will be downloaded to. If directory the base name of the URL on the remote server will be used. |
|
||||||
|
| miq_image_checksum | UNDEF | If a checksum is defined, the digest of the destination file will be calculated after it is downloaded to ensure its integrity and verify that the transfer completed successfully. Format: :, e.g. checksum="sha256:D98291AC[...]B6DC7B97". |
|
||||||
|
|
||||||
|
Engine login variables:
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|---------------------|-------------------|-----------------------------------------|
|
||||||
|
| engine_user | UNDEF | The user to access the engine. |
|
||||||
|
| engine_password | UNDEF | The password of the 'engine_user'. |
|
||||||
|
| engine_fqdn | UNDEF | The FQDN of the engine. |
|
||||||
|
| engine_ca | UNDEF | The path to the engine's CA certificate.|
|
||||||
|
|
||||||
|
Virtual machine variables:
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|-----------------------|---------------------|----------------------------------------------------------------|
|
||||||
|
| miq_vm_name | manageiq_gaprindashvili-3 | The name of the ManageIQ virtual machine. |
|
||||||
|
| miq_vm_cluster | Default | The cluster of the virtual machine. |
|
||||||
|
| miq_vm_memory | 16GiB | The virtual machine's system memory. |
|
||||||
|
| miq_vm_memory_guaranteed | UNDEF | Amount of minimal guaranteed memory of the Virtual Machine. miq_vm_memory_guaranteed parameter can't be lower than miq_vm_memory parameter. |
|
||||||
|
| miq_vm_memory_max | UNDEF | Upper bound of virtual machine memory up to which memory hot-plug can be performed. |
|
||||||
|
| miq_vm_cpu | 4 | The number of virtual machine CPU cores. |
|
||||||
|
| miq_vm_cpu_shares | UNDEF | Set a CPU shares for this Virtual Machine. |
|
||||||
|
| miq_vm_cpu_sockets | UNDEF | Number of virtual CPUs sockets of the Virtual Machine. |
|
||||||
|
| miq_vm_cpu_threads | UNDEF | Number of virtual CPUs threads of the Virtual Machine. |
|
||||||
|
| miq_vm_os | rhel_7x64 | The virtual machine operating system. |
|
||||||
|
| miq_vm_root_password | `miq_app_password` | The root password for the virtual machine. |
|
||||||
|
| miq_vm_cloud_init | UNDEF | The cloud init dictionary to be passed to the virtual machine. |
|
||||||
|
| miq_vm_high_availability | true | If yes ManageIQ virtual machine will be set as highly available. |
|
||||||
|
| miq_vm_high_availability_priority | 50 | Indicates the priority of the virtual machine inside the run and migration queues. The value is an integer between 0 and 100. The higher the value, the higher the priority. |
|
||||||
|
| miq_vm_delete_protected | true | If yes ManageIQ virtual machine will be set as delete protected. |
|
||||||
|
| miq_debug_create | false | If true log sensitive data, useful for debug purposes. |
|
||||||
|
| miq_wait_for_ip_version | v4 | Specify which IP version should be wait for. Either v4 or v6. |
|
||||||
|
|
||||||
|
Virtual machine main disks variables (e.g. operating system):
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|---------------------|----------------------|-----------------------------------------|
|
||||||
|
| miq_vm_disk_name | `miq_vm_name` | The name of the virtual machine disk. |
|
||||||
|
| miq_vm_disk_storage | UNDEF | The target storage domain of the disk. |
|
||||||
|
| miq_vm_disk_size | Size of qcow disk | The virtual machine disk size. |
|
||||||
|
| miq_vm_disk_interface | virtio_scsi | The virtual machine disk interface type.|
|
||||||
|
| miq_vm_disk_format | cow | The format of the virtual machine disk. |
|
||||||
|
|
||||||
|
Virtual machine extra disks (e.g. database, log, tmp): a dict named
|
||||||
|
`miq_vm_disks` allows to describe each of the extra disks (see example
|
||||||
|
playbook). Note, that this works only with CFME.
|
||||||
|
For each disk, the following attributes can be set:
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|-----------|---------------|----------------------------------------------------------------------|
|
||||||
|
| name | `miq_vm_name`_`type` | The name of the virtual machine disk. |
|
||||||
|
| size | UNDEF | The virtual machine disk size (`XXGiB`). |
|
||||||
|
| interface | virtio_scsi | The virtual machine disk interface type (`virtio` or `virtio_scsi`). `virtio_scsi` is recommended, as `virtio` has low limit of count of disks. |
|
||||||
|
| format | UNDEF | The format of the virtual machine disk (`raw` or `cow`). |
|
||||||
|
| timeout | UNDEF | Timeout of disk creation. |
|
||||||
|
|
||||||
|
Virtual machine NICs variables:
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|---------------------|-------------------|------------------------------------------------------|
|
||||||
|
| miq_vm_nics | {'name': 'nic1', 'profile_name': 'ovirtmgmt', 'interaface': 'virtio'} | List of dictionaries that defines the virtual machine network interfaces. |
|
||||||
|
|
||||||
|
The item in `miq_vm_nics` list of can contain following attributes:
|
||||||
|
|
||||||
|
| Name | Default value | |
|
||||||
|
|--------------------|----------------|----------------------------------------------|
|
||||||
|
| name | UNDEF | The name of the network interface. |
|
||||||
|
| interface | UNDEF | Type of the network interface. |
|
||||||
|
| mac_address | UNDEF | Custom MAC address of the network interface, by default it's obtained from MAC pool. |
|
||||||
|
| network | UNDEF | Logical network which the VM network interface should use. If network is not specified, then Empty network is used. |
|
||||||
|
| profile | UNDEF | Virtual network interface profile to be attached to VM network interface. |
|
||||||
|
|
||||||
|
ManageIQ variables:
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|--------------------|---------------------|----------------------------------------------------------------------------|
|
||||||
|
| miq_app_username | admin | The username used to login to ManageIQ. |
|
||||||
|
| miq_app_password | smartvm | The password of user specific in username used to login to ManageIQ. |
|
||||||
|
| miq_username | admin | Alias of `miq_app_username` for backward compatibility. |
|
||||||
|
| miq_password | smartvm | Alias of `miq_app_password` for backward compatibility. |
|
||||||
|
| miq_db_username | root | The username to connect to the database. |
|
||||||
|
| miq_db_password | `miq_app_password` | The password of user specific in username used to connect to the database. |
|
||||||
|
| miq_region | 0 | The ManageIQ region created in the database. Note: Works only with CFME. |
|
||||||
|
| miq_company | My Company | The company name of the appliance. |
|
||||||
|
| miq_disabled_roles | [] | List of ManageIQ server roles to disable on the appliance. |
|
||||||
|
| miq_enabled_roles | [] | List of ManageIQ server roles to enable on the appliance. |
|
||||||
|
|
||||||
|
Both on ManageIQ and CloudForms, the default enabled server roles are:
|
||||||
|
- `automate` - Automation Engine
|
||||||
|
- `database_operations` - Database Operations
|
||||||
|
- `event` - Event Monitor
|
||||||
|
- `ems_inventory` - Provider Inventory
|
||||||
|
- `ems_operations` - Provider Operations
|
||||||
|
- `reporting` - Reporting
|
||||||
|
- `scheduler` - Scheduler
|
||||||
|
- `smartstate` - SmartState Analysis
|
||||||
|
- `user_interface` - User Interface
|
||||||
|
- `websocket` - Websocket
|
||||||
|
- `web_services` - Web Services
|
||||||
|
|
||||||
|
RHV provider and RHV metrics variables:
|
||||||
|
|
||||||
|
| Name | Default value | Description |
|
||||||
|
|-----------------------|----------------|--------------------------------------------------------|
|
||||||
|
| miq_rhv_provider_name | RHV provider | Name of the RHV provider to be displayed in ManageIQ. |
|
||||||
|
| metrics_fqdn | UNDEF | FQDN of the oVirt/RHV metrics. |
|
||||||
|
| metrics_user | engine_history | The user to connection to metrics server. |
|
||||||
|
| metrics_password | "" | The password of the `metrics_user` . |
|
||||||
|
| metrics_port | 5432 | Port to connect to oVirt/RHV metrics. |
|
||||||
|
| metrics_db_name | ovirt_engine_history | Database name of the oVirt engine metrics database. |
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
No.
|
||||||
|
|
||||||
|
Example Playbook
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Note that for passwords you should use Ansible vault.
|
||||||
|
|
||||||
|
Here is an example how to deploy CFME:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Deploy CFME to oVirt engine
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: no
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
# Contains encrypted `engine_password` varibale using ansible-vault
|
||||||
|
- passwords.yml
|
||||||
|
|
||||||
|
vars:
|
||||||
|
engine_fqdn: ovirt-engine.example.com
|
||||||
|
engine_user: admin@internal
|
||||||
|
|
||||||
|
miq_qcow_url: https://cdn.example.com/cfme-rhevm-5.9.1.2-1.x86_64.qcow2
|
||||||
|
miq_vm_name: cfme_59
|
||||||
|
miq_vm_cluster: mycluster
|
||||||
|
miq_vm_cloud_init:
|
||||||
|
host_name: "{{ miq_vm_name }}"
|
||||||
|
miq_vm_disks:
|
||||||
|
database:
|
||||||
|
name: "{{ miq_vm_name }}_database"
|
||||||
|
size: 10GiB
|
||||||
|
interface: virtio_scsi
|
||||||
|
format: raw
|
||||||
|
log:
|
||||||
|
name: "{{ miq_vm_name }}_log"
|
||||||
|
size: 10GiB
|
||||||
|
interface: virtio_scsi
|
||||||
|
format: cow
|
||||||
|
tmp:
|
||||||
|
name: "{{ miq_vm_name }}_tmp"
|
||||||
|
size: 10GiB
|
||||||
|
interface: virtio_scsi
|
||||||
|
format: cow
|
||||||
|
miq_disabled_roles:
|
||||||
|
- smartstate
|
||||||
|
miq_enabled_roles:
|
||||||
|
- notifier
|
||||||
|
- ems_metrics_coordinator
|
||||||
|
- ems_metrics_collector
|
||||||
|
- ems_metrics_processor
|
||||||
|
- embedded_ansible
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- ovirt.manageiq
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is an example how to deploy ManageIQ:
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
- name: oVirt ManageIQ deployment
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
# Contains encrypted `engine_password` and `metrics_password`
|
||||||
|
# varibale using ansible-vault
|
||||||
|
- passwords.yml
|
||||||
|
|
||||||
|
vars:
|
||||||
|
engine_fqdn: ovirt.example.com
|
||||||
|
engine_user: admin@internal
|
||||||
|
engine_cafile: /etc/pki/ovirt-engine/ca.pem
|
||||||
|
|
||||||
|
miq_qcow_url: http://releases.manageiq.org/manageiq-ovirt-gaprindashvili-5.qc2
|
||||||
|
miq_vm_name: manageiq_g5
|
||||||
|
miq_vm_cluster: mycluster
|
||||||
|
|
||||||
|
metrics_fqdn: metrics.example.com
|
||||||
|
metrics_port: 8443
|
||||||
|
metrics_user: admin
|
||||||
|
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- ovirt.manageiq
|
||||||
|
`````````````````````````````````
|
||||||
6
roles/ovirt.manageiq/automation.yaml
Normal file
6
roles/ovirt.manageiq/automation.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
distros:
|
||||||
|
- fc29
|
||||||
|
- fc28
|
||||||
|
- el7
|
||||||
|
release_branches:
|
||||||
|
master: [ "ovirt-master", "ovirt-4.3", "ovirt-4.2" ]
|
||||||
8
roles/ovirt.manageiq/automation/README.md
Normal file
8
roles/ovirt.manageiq/automation/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Continuous Integration Scripts
|
||||||
|
==============================
|
||||||
|
|
||||||
|
This directory contains scripts for Continuous Integration provided by
|
||||||
|
[oVirt Jenkins](http://jenkins.ovirt.org/)
|
||||||
|
system and follows the standard defined in
|
||||||
|
[Build and test standards](http://www.ovirt.org/CI/Build_and_test_standards)
|
||||||
|
wiki page.
|
||||||
1
roles/ovirt.manageiq/automation/build-artifacts-manual.req
Symbolic link
1
roles/ovirt.manageiq/automation/build-artifacts-manual.req
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
build-artifacts.req
|
||||||
29
roles/ovirt.manageiq/automation/build-artifacts-manual.sh
Executable file
29
roles/ovirt.manageiq/automation/build-artifacts-manual.sh
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash -xe
|
||||||
|
|
||||||
|
# remove any previous artifacts
|
||||||
|
rm -rf output
|
||||||
|
make clean
|
||||||
|
|
||||||
|
# Get the tarball
|
||||||
|
./build.sh dist
|
||||||
|
|
||||||
|
# create the src.rpm, assuming the tarball is in the project's directory
|
||||||
|
rpmbuild \
|
||||||
|
-D "_srcrpmdir $PWD/output" \
|
||||||
|
-D "_topmdir $PWD/rpmbuild" \
|
||||||
|
-ts ./*.gz
|
||||||
|
|
||||||
|
# install any build requirements
|
||||||
|
yum-builddep output/*src.rpm
|
||||||
|
|
||||||
|
# create the rpms
|
||||||
|
rpmbuild \
|
||||||
|
-D "_rpmdir $PWD/output" \
|
||||||
|
-D "_topmdir $PWD/rpmbuild" \
|
||||||
|
--rebuild output/*.src.rpm
|
||||||
|
|
||||||
|
# Store any relevant artifacts in exported-artifacts for the ci system to
|
||||||
|
# archive
|
||||||
|
[[ -d exported-artifacts ]] || mkdir -p exported-artifacts
|
||||||
|
find output -iname \*rpm -exec mv "{}" exported-artifacts/ \;
|
||||||
|
mv ./*tar.gz exported-artifacts/
|
||||||
3
roles/ovirt.manageiq/automation/build-artifacts.packages
Normal file
3
roles/ovirt.manageiq/automation/build-artifacts.packages
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
yum-utils
|
||||||
|
ansible
|
||||||
|
git
|
||||||
29
roles/ovirt.manageiq/automation/build-artifacts.sh
Executable file
29
roles/ovirt.manageiq/automation/build-artifacts.sh
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash -xe
|
||||||
|
|
||||||
|
# remove any previous artifacts
|
||||||
|
rm -rf output
|
||||||
|
rm -f ./*tar.gz
|
||||||
|
|
||||||
|
# Get the tarball
|
||||||
|
./build.sh dist
|
||||||
|
|
||||||
|
# create the src.rpm
|
||||||
|
rpmbuild \
|
||||||
|
-D "_srcrpmdir $PWD/output" \
|
||||||
|
-D "_topmdir $PWD/rpmbuild" \
|
||||||
|
-ts ./*.gz
|
||||||
|
|
||||||
|
# install any build requirements
|
||||||
|
yum-builddep output/*src.rpm
|
||||||
|
|
||||||
|
# create the rpms
|
||||||
|
rpmbuild \
|
||||||
|
-D "_rpmdir $PWD/output" \
|
||||||
|
-D "_topmdir $PWD/rpmbuild" \
|
||||||
|
--rebuild output/*.src.rpm
|
||||||
|
|
||||||
|
# Store any relevant artifacts in exported-artifacts for the ci system to
|
||||||
|
# archive
|
||||||
|
[[ -d exported-artifacts ]] || mkdir -p exported-artifacts
|
||||||
|
find output -iname \*rpm -exec mv "{}" exported-artifacts/ \;
|
||||||
|
mv ./*tar.gz exported-artifacts/
|
||||||
3
roles/ovirt.manageiq/automation/check-patch.packages
Normal file
3
roles/ovirt.manageiq/automation/check-patch.packages
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
yum-utils
|
||||||
|
git
|
||||||
|
ansible
|
||||||
27
roles/ovirt.manageiq/automation/check-patch.sh
Executable file
27
roles/ovirt.manageiq/automation/check-patch.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash -xe
|
||||||
|
|
||||||
|
# remove any previous artifacts
|
||||||
|
rm -rf output
|
||||||
|
rm -f ./*tar.gz
|
||||||
|
|
||||||
|
# Get the tarball
|
||||||
|
./build.sh dist
|
||||||
|
|
||||||
|
# create the src.rpm
|
||||||
|
rpmbuild \
|
||||||
|
-D "_srcrpmdir $PWD/output" \
|
||||||
|
-D "_topmdir $PWD/rpmbuild" \
|
||||||
|
-ts ./*.gz
|
||||||
|
|
||||||
|
# install any build requirements
|
||||||
|
yum-builddep output/*src.rpm
|
||||||
|
|
||||||
|
# create the rpms
|
||||||
|
rpmbuild \
|
||||||
|
-D "_rpmdir $PWD/output" \
|
||||||
|
-D "_topmdir $PWD/rpmbuild" \
|
||||||
|
--rebuild output/*.src.rpm
|
||||||
|
|
||||||
|
[[ -d exported-artifacts ]] || mkdir -p exported-artifacts
|
||||||
|
find output -iname \*rpm -exec mv "{}" exported-artifacts/ \;
|
||||||
|
mv *.tar.gz exported-artifacts
|
||||||
60
roles/ovirt.manageiq/build.sh
Executable file
60
roles/ovirt.manageiq/build.sh
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
VERSION="1.1.14"
|
||||||
|
MILESTONE=
|
||||||
|
RPM_RELEASE="1"
|
||||||
|
|
||||||
|
ROLE_NAME="ovirt.manageiq"
|
||||||
|
PACKAGE_NAME="ovirt-ansible-manageiq"
|
||||||
|
PREFIX=/usr/local
|
||||||
|
DATAROOT_DIR=$PREFIX/share
|
||||||
|
ROLES_DATAROOT_DIR=$DATAROOT_DIR/ansible/roles
|
||||||
|
DOC_DIR=$DATAROOT_DIR/doc
|
||||||
|
PKG_DATA_DIR=${PKG_DATA_DIR:-$ROLES_DATAROOT_DIR/$PACKAGE_NAME}
|
||||||
|
PKG_DATA_DIR_ORIG=${PKG_DATA_DIR_ORIG:-$PKG_DATA_DIR}
|
||||||
|
PKG_DOC_DIR=${PKG_DOC_DIR:-$DOC_DIR/$PACKAGE_NAME}
|
||||||
|
ROLENAME_LEGACY="${ROLENAME_LEGACY:-$ROLES_DATAROOT_DIR/ovirt-manageiq}"
|
||||||
|
ROLENAME_LEGACY_UPPERCASE="${ROLENAME_LEGACY_UPPERCASE:-$ROLES_DATAROOT_DIR/oVirt.manageiq}"
|
||||||
|
|
||||||
|
RPM_VERSION=$VERSION
|
||||||
|
PACKAGE_VERSION=$VERSION
|
||||||
|
[ -n "$MILESTONE" ] && PACKAGE_VERSION+="_$MILESTONE"
|
||||||
|
DISPLAY_VERSION=$PACKAGE$VERSION
|
||||||
|
|
||||||
|
TARBALL="$PACKAGE_NAME-$PACKAGE_VERSION.tar.gz"
|
||||||
|
|
||||||
|
dist() {
|
||||||
|
echo "Creating tar archive '$TARBALL' ... "
|
||||||
|
sed \
|
||||||
|
-e "s|@RPM_VERSION@|$RPM_VERSION|g" \
|
||||||
|
-e "s|@RPM_RELEASE@|$RPM_RELEASE|g" \
|
||||||
|
-e "s|@PACKAGE_NAME@|$PACKAGE_NAME|g" \
|
||||||
|
-e "s|@PACKAGE_VERSION@|$PACKAGE_VERSION|g" \
|
||||||
|
< ovirt-ansible-manageiq.spec.in > ovirt-ansible-manageiq.spec
|
||||||
|
|
||||||
|
git ls-files | tar --files-from /proc/self/fd/0 -czf "$TARBALL" ovirt-ansible-manageiq.spec
|
||||||
|
echo "tar archive '$TARBALL' created."
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
echo "Installing data..."
|
||||||
|
mkdir -p $PKG_DATA_DIR
|
||||||
|
mkdir -p $PKG_DOC_DIR
|
||||||
|
|
||||||
|
# Create a symlink, so legacy role name does work:
|
||||||
|
ln -f -s $PKG_DATA_DIR_ORIG $ROLENAME_LEGACY
|
||||||
|
|
||||||
|
# Create a symlink, so legacy role name does work with upper case:
|
||||||
|
ln -f -s $PKG_DATA_DIR_ORIG $ROLENAME_LEGACY_UPPERCASE
|
||||||
|
|
||||||
|
cp -pR defaults/ $PKG_DATA_DIR
|
||||||
|
cp -pR filter_plugins/ $PKG_DATA_DIR
|
||||||
|
cp -pR library/ $PKG_DATA_DIR
|
||||||
|
cp -pR tasks/ $PKG_DATA_DIR
|
||||||
|
cp -pR templates/ $PKG_DATA_DIR
|
||||||
|
cp -pR vars/ $PKG_DATA_DIR
|
||||||
|
|
||||||
|
echo "Installation done."
|
||||||
|
}
|
||||||
|
|
||||||
|
$1
|
||||||
80
roles/ovirt.manageiq/defaults/main.yml
Normal file
80
roles/ovirt.manageiq/defaults/main.yml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
### This option disables no_log of tasks using sensistive data:
|
||||||
|
miq_debug_create: false
|
||||||
|
|
||||||
|
### Wait for IP version (v4 or v6):
|
||||||
|
miq_wait_for_ip_version: v4
|
||||||
|
|
||||||
|
### ManageIQ/CloudForms ###
|
||||||
|
miq_image_path: /tmp
|
||||||
|
|
||||||
|
# QCOW2 ManageIQ/CloudForms image URL:
|
||||||
|
miq_qcow_url: http://releases.manageiq.org/manageiq-ovirt-gaprindashvili-5.qc2
|
||||||
|
|
||||||
|
# ManageIQ/CloudForms application credentials
|
||||||
|
# We keep miq_{username,password} for backward compatibility
|
||||||
|
miq_username: admin
|
||||||
|
miq_password: smartvm
|
||||||
|
miq_app_username: "{{ miq_username }}"
|
||||||
|
miq_app_password: "{{ miq_password }}"
|
||||||
|
|
||||||
|
# ManageIQ/CloudForms database credentials
|
||||||
|
miq_db_username: root
|
||||||
|
miq_db_password: "{{ miq_app_password }}"
|
||||||
|
|
||||||
|
# ManageIQ/CloudForms region
|
||||||
|
miq_region: 0
|
||||||
|
miq_region_id: 1
|
||||||
|
|
||||||
|
# ManageIQ/CloudForms company name
|
||||||
|
miq_company: My Company
|
||||||
|
|
||||||
|
# Providers:
|
||||||
|
miq_rhv_provider_name: RHV provider
|
||||||
|
miq_initialize: true
|
||||||
|
|
||||||
|
### oVirt/RHV ###
|
||||||
|
# VM variables:
|
||||||
|
miq_vm_name: manageiq_gaprindashvili-5
|
||||||
|
miq_vm_cluster: Default
|
||||||
|
miq_vm_memory: 16GiB
|
||||||
|
miq_vm_cpu: 4
|
||||||
|
miq_vm_os: rhel_7x64
|
||||||
|
miq_vm_root_password: "{{ miq_app_password }}"
|
||||||
|
miq_vm_high_availability: true
|
||||||
|
miq_vm_high_availability_priority: 50
|
||||||
|
miq_vm_delete_protected: true
|
||||||
|
|
||||||
|
# Vm disks
|
||||||
|
miq_vm_disk_interface: virtio
|
||||||
|
miq_vm_disk_format: cow
|
||||||
|
miq_disk_deploy_failed: false
|
||||||
|
|
||||||
|
# Additional disks.
|
||||||
|
# Default one is database disk.
|
||||||
|
miq_vm_disks:
|
||||||
|
database:
|
||||||
|
name: "{{ miq_vm_name }}_database"
|
||||||
|
size: 50GiB
|
||||||
|
interface: virtio_scsi
|
||||||
|
format: raw
|
||||||
|
timeout: 900
|
||||||
|
|
||||||
|
# Vm NICS:
|
||||||
|
miq_vm_nics:
|
||||||
|
- name: nic1
|
||||||
|
profile_name: ovirtmgmt
|
||||||
|
interface: virtio
|
||||||
|
|
||||||
|
# Metrics DB name
|
||||||
|
metrics_db_name: ovirt_engine_history
|
||||||
|
metrics_port: 5432
|
||||||
|
metrics_user: engine_history
|
||||||
|
metrics_password: ''
|
||||||
|
|
||||||
|
# ManageIQ/CloudForms roles
|
||||||
|
miq_disabled_roles: []
|
||||||
|
miq_enabled_roles: []
|
||||||
|
|
||||||
|
# Command to initialize cloudforms
|
||||||
|
miq_init_cmd: "appliance_console_cli -i -r {{ miq_region }} -U {{ miq_db_username }} -p '{{ miq_db_password }}' -k -f"
|
||||||
48
roles/ovirt.manageiq/examples/cfme.yml
Normal file
48
roles/ovirt.manageiq/examples/cfme.yml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
- name: RHV CFME deployment
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
# Contains encrypted `engine_password` and `metrics_password`
|
||||||
|
# varibale using ansible-vault
|
||||||
|
- passwords.yml
|
||||||
|
|
||||||
|
vars:
|
||||||
|
engine_fqdn: ovirt-engine.example.com
|
||||||
|
engine_user: admin@internal
|
||||||
|
|
||||||
|
miq_vm_name: cfme_59
|
||||||
|
miq_qcow_url: https://cdn.example.com/cfme-rhevm-5.9.1.2-1.x86_64.qcow2
|
||||||
|
miq_vm_cluster: mycluster
|
||||||
|
miq_vm_root_password: securepassword
|
||||||
|
miq_vm_cloud_init:
|
||||||
|
host_name: "{{ miq_vm_name }}"
|
||||||
|
miq_vm_disks:
|
||||||
|
database:
|
||||||
|
name: "{{ miq_vm_name }}_database"
|
||||||
|
size: 10GiB
|
||||||
|
interface: virtio_scsi
|
||||||
|
format: raw
|
||||||
|
log:
|
||||||
|
name: "{{ miq_vm_name }}_log"
|
||||||
|
size: 10GiB
|
||||||
|
interface: virtio_scsi
|
||||||
|
format: cow
|
||||||
|
tmp:
|
||||||
|
name: "{{ miq_vm_name }}_tmp"
|
||||||
|
size: 10GiB
|
||||||
|
interface: virtio_scsi
|
||||||
|
format: raw
|
||||||
|
miq_disabled_roles:
|
||||||
|
- smartstate
|
||||||
|
miq_enabled_roles:
|
||||||
|
- notifier
|
||||||
|
- ems_metrics_coordinator
|
||||||
|
- ems_metrics_collector
|
||||||
|
- ems_metrics_processor
|
||||||
|
- embedded_ansible
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- ovirt.manageiq
|
||||||
27
roles/ovirt.manageiq/examples/manageiq.yml
Normal file
27
roles/ovirt.manageiq/examples/manageiq.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
- name: oVirt ManageIQ deployment
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars_files:
|
||||||
|
# Contains encrypted `engine_password` and `metrics_password`
|
||||||
|
# varibale using ansible-vault
|
||||||
|
- passwords.yml
|
||||||
|
|
||||||
|
vars:
|
||||||
|
engine_fqdn: ovirt.example.com
|
||||||
|
engine_user: admin@internal
|
||||||
|
engine_cafile: /etc/pki/ovirt-engine/ca.pem
|
||||||
|
|
||||||
|
miq_qcow_url: http://releases.manageiq.org/manageiq-ovirt-gaprindashvili-3.qc2
|
||||||
|
miq_vm_name: manageiq_g3
|
||||||
|
miq_vm_cluster: mycluster
|
||||||
|
|
||||||
|
metrics_fqdn: metrics.example.com
|
||||||
|
metrics_port: 8443
|
||||||
|
metrics_user: admin
|
||||||
|
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- ovirt.manageiq
|
||||||
1
roles/ovirt.manageiq/examples/ovirt.manageiq
Symbolic link
1
roles/ovirt.manageiq/examples/ovirt.manageiq
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../
|
||||||
12
roles/ovirt.manageiq/examples/passwords.yml
Normal file
12
roles/ovirt.manageiq/examples/passwords.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
# As an example this file is keep in plaintext, if you want to
|
||||||
|
# encrypt this file, please execute following command:
|
||||||
|
#
|
||||||
|
# $ ansible-vault encrypt passwords.yml
|
||||||
|
#
|
||||||
|
# It will ask you for a password, which you must then pass to
|
||||||
|
# ansible interactively when executing the playbook.
|
||||||
|
#
|
||||||
|
# $ ansible-playbook myplaybook.yml --ask-vault-pass
|
||||||
|
#
|
||||||
|
engine_password: 123456
|
||||||
73
roles/ovirt.manageiq/filter_plugins/ovirtvmip.py
Normal file
73
roles/ovirt.manageiq/filter_plugins/ovirtvmip.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
'Module to create filter to find IP addresses in VMs'
|
||||||
|
class FilterModule(object):
|
||||||
|
'Filter for IP addresses on newly created VMs'
|
||||||
|
def filters(self):
|
||||||
|
'Define filters'
|
||||||
|
return {
|
||||||
|
'ovirtvmip': self.ovirtvmip,
|
||||||
|
'ovirtvmips': self.ovirtvmips,
|
||||||
|
'ovirtvmipv4': self.ovirtvmipv4,
|
||||||
|
'ovirtvmipsv4': self.ovirtvmipsv4,
|
||||||
|
'ovirtvmipv6': self.ovirtvmipv6,
|
||||||
|
'ovirtvmipsv6': self.ovirtvmipsv6,
|
||||||
|
}
|
||||||
|
|
||||||
|
def ovirtvmip(self, ovirt_vms, attr=None):
|
||||||
|
'Return first IP'
|
||||||
|
return self.__get_first_ip(self.ovirtvmips(ovirt_vms, attr))
|
||||||
|
|
||||||
|
def ovirtvmips(self, ovirt_vms, attr=None):
|
||||||
|
'Return list of IPs'
|
||||||
|
return self._parse_ips(ovirt_vms, attr=attr)
|
||||||
|
|
||||||
|
def ovirtvmipv4(self, ovirt_vms, attr=None):
|
||||||
|
'Return first IPv4 IP'
|
||||||
|
return self.__get_first_ip(self.ovirtvmipsv4(ovirt_vms, attr))
|
||||||
|
|
||||||
|
def ovirtvmipsv4(self, ovirt_vms, attr=None):
|
||||||
|
'Return list of IPv4 IPs'
|
||||||
|
return self._parse_ips(ovirt_vms, lambda version: version == 'v4', attr)
|
||||||
|
|
||||||
|
def ovirtvmipv6(self, ovirt_vms, attr=None):
|
||||||
|
'Return first IPv6 IP'
|
||||||
|
return self.__get_first_ip(self.ovirtvmipsv6(ovirt_vms, attr))
|
||||||
|
|
||||||
|
def ovirtvmipsv6(self, ovirt_vms, attr=None):
|
||||||
|
'Return list of IPv6 IPs'
|
||||||
|
return self._parse_ips(ovirt_vms, lambda version: version == 'v6', attr)
|
||||||
|
|
||||||
|
def _parse_ips(self, ovirt_vms, version_condition=lambda version: True, attr=None):
|
||||||
|
if not isinstance(ovirt_vms, list):
|
||||||
|
ovirt_vms = [ovirt_vms]
|
||||||
|
|
||||||
|
if attr is None:
|
||||||
|
return self._parse_ips_aslist(ovirt_vms, version_condition)
|
||||||
|
else:
|
||||||
|
return self._parse_ips_asdict(ovirt_vms, version_condition, attr)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse_ips_asdict(ovirt_vms, version_condition=lambda version: True, attr=None):
|
||||||
|
vm_ips = {}
|
||||||
|
for ovirt_vm in ovirt_vms:
|
||||||
|
ips = []
|
||||||
|
for device in ovirt_vm.get('reported_devices', []):
|
||||||
|
for curr_ip in device.get('ips', []):
|
||||||
|
if version_condition(curr_ip.get('version')):
|
||||||
|
ips.append(curr_ip.get('address'))
|
||||||
|
vm_ips[ovirt_vm.get(attr)] = ips
|
||||||
|
return vm_ips
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse_ips_aslist(ovirt_vms, version_condition=lambda version: True):
|
||||||
|
ips = []
|
||||||
|
for ovirt_vm in ovirt_vms:
|
||||||
|
for device in ovirt_vm.get('reported_devices', []):
|
||||||
|
for curr_ip in device.get('ips', []):
|
||||||
|
if version_condition(curr_ip.get('version')):
|
||||||
|
ips.append(curr_ip.get('address'))
|
||||||
|
return ips
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __get_first_ip(res):
|
||||||
|
return res[0] if isinstance(res, list) and res else res
|
||||||
1
roles/ovirt.manageiq/meta/.galaxy_install_info
Normal file
1
roles/ovirt.manageiq/meta/.galaxy_install_info
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{install_date: 'Wed Aug 28 12:51:49 2019', version: 1.1.14}
|
||||||
20
roles/ovirt.manageiq/meta/main.yml
Normal file
20
roles/ovirt.manageiq/meta/main.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: Ondra Machacek
|
||||||
|
description: Role to deploy ManageIQ/CloudForms into oVirt/RHV.
|
||||||
|
company: Red Hat, Inc.
|
||||||
|
|
||||||
|
license: Apache License 2.0
|
||||||
|
|
||||||
|
min_ansible_version: 2.5
|
||||||
|
|
||||||
|
platforms:
|
||||||
|
- name: EL
|
||||||
|
versions:
|
||||||
|
- 7
|
||||||
|
- name: Fedora
|
||||||
|
versions:
|
||||||
|
- 24
|
||||||
|
|
||||||
|
galaxy_tags: [manageiq, cloudforms, ovirt, rhv, rhev, virtualization]
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
133
roles/ovirt.manageiq/ovirt-ansible-manageiq.spec.in
Normal file
133
roles/ovirt.manageiq/ovirt-ansible-manageiq.spec.in
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
%global rolename manageiq
|
||||||
|
%global roleprefix ovirt.
|
||||||
|
%global roleprefix_legacy ovirt-
|
||||||
|
%global roleprefix_legacy_uppercase oVirt.
|
||||||
|
%global ansible_roles_dir ansible/roles
|
||||||
|
|
||||||
|
Name: @PACKAGE_NAME@
|
||||||
|
Summary: Ansible role to create ManageIQ or CloudForms virtual machine from qcow image
|
||||||
|
Version: @RPM_VERSION@
|
||||||
|
Release: @RPM_RELEASE@%{?release_suffix}%{?dist}
|
||||||
|
Source0: http://resources.ovirt.org/pub/src/@PACKAGE_NAME@/@PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz
|
||||||
|
License: ASL 2.0
|
||||||
|
Group: Virtualization/Management
|
||||||
|
BuildArch: noarch
|
||||||
|
Url: http://www.ovirt.org
|
||||||
|
|
||||||
|
Requires: ansible >= 2.7.2
|
||||||
|
|
||||||
|
%description
|
||||||
|
This Ansible role provide funtionality to create ManageIQ or CloudForms virtual
|
||||||
|
machine from qcow image.
|
||||||
|
|
||||||
|
%pretrans -p <lua>
|
||||||
|
-- Remove the legacy directory before installing the symlink. This is known issue in RPM:
|
||||||
|
-- https://fedoraproject.org/wiki/Packaging:Directory_Replacement
|
||||||
|
path_dash = "%{_datadir}/%{ansible_roles_dir}/%{roleprefix_legacy}%{rolename}"
|
||||||
|
path_uppercase = "%{_datadir}/%{ansible_roles_dir}/%{roleprefix_legacy_uppercase}%{rolename}"
|
||||||
|
|
||||||
|
st = posix.stat(path_dash)
|
||||||
|
if st and st.type == "directory" then
|
||||||
|
os.execute('rm -rf "'..path_dash..'"')
|
||||||
|
end
|
||||||
|
|
||||||
|
st = posix.stat(path_uppercase)
|
||||||
|
if st and st.type == "directory" then
|
||||||
|
os.execute('rm -rf "'..path_uppercase..'"')
|
||||||
|
end
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -c -q
|
||||||
|
|
||||||
|
%build
|
||||||
|
|
||||||
|
%install
|
||||||
|
export PKG_DATA_DIR_ORIG=%{_datadir}/%{ansible_roles_dir}/%{roleprefix}%{rolename}
|
||||||
|
export PKG_DATA_DIR=%{buildroot}$PKG_DATA_DIR_ORIG
|
||||||
|
export PKG_DOC_DIR=%{buildroot}%{_pkgdocdir}
|
||||||
|
export ROLENAME_LEGACY=%{buildroot}%{_datadir}/%{ansible_roles_dir}/%{roleprefix_legacy}%{rolename}
|
||||||
|
export ROLENAME_LEGACY_UPPERCASE=%{buildroot}%{_datadir}/%{ansible_roles_dir}/%{roleprefix_legacy_uppercase}%{rolename}
|
||||||
|
sh build.sh install
|
||||||
|
|
||||||
|
%files
|
||||||
|
%{_datadir}/%{ansible_roles_dir}/%{roleprefix}%{rolename}
|
||||||
|
%{_datadir}/%{ansible_roles_dir}/%{roleprefix_legacy}%{rolename}
|
||||||
|
%{_datadir}/%{ansible_roles_dir}/%{roleprefix_legacy_uppercase}%{rolename}
|
||||||
|
|
||||||
|
%doc README.md
|
||||||
|
%doc examples/
|
||||||
|
|
||||||
|
%license LICENSE
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Wed May 15 2019 Ondra Machacek <omachace@redhat.com> - 1.1.14-1
|
||||||
|
- Don't try to re-init miq when initiailized.
|
||||||
|
|
||||||
|
* Thu Nov 29 2018 Ondra Machacek <omachace@redhat.com> - 1.1.13-1
|
||||||
|
- Change default disks interface to virtio_scsi.
|
||||||
|
- Support ovirt.manageiq name.
|
||||||
|
- Require Ansible 2.7.2.
|
||||||
|
|
||||||
|
* Tue Sep 18 2018 Ondra Machacek <omachace@redhat.com> - 1.1.12-1
|
||||||
|
- Document additional disks works with CFME only. rhbz#1627020
|
||||||
|
- Skip region settings in case of ManageIQ. rhbz#1627018
|
||||||
|
- Don't fail if miq_vm_disk_storage is defined. rhbz#1624836
|
||||||
|
- RHV provider can be added using env vars. rhbz#1613914
|
||||||
|
- Document that dry mode is unsupported. rhbz#1614314
|
||||||
|
- Support using engine_fqdn instead of url. rhbz#1613914
|
||||||
|
- Use corect IDs for MiQ region number. rhbz#1592857
|
||||||
|
- Add miq_wait_for_ip_version variable. rhbz#1613723
|
||||||
|
- Add miq_debug_create to disable no_log. gh#62
|
||||||
|
- Add support for OVIRT_HOSTNAME env var.
|
||||||
|
- Add possibility to login external from role.
|
||||||
|
- Fix ternary operator in ovirt_auth. rhbz#1584772
|
||||||
|
|
||||||
|
* Mon Jul 9 2018 Ondra Machacek <omachace@redhat.com> - 1.1.11-1
|
||||||
|
- Can't set password via miq_app_password variable. rhbz#1590336
|
||||||
|
|
||||||
|
* Thu Jun 7 2018 Ondra Machacek <omachace@redhat.com> - 1.1.10-1
|
||||||
|
- Add /vars directory to RPM. rhbz@1588415
|
||||||
|
|
||||||
|
* Wed May 30 2018 Ondra Machacek <omachace@redhat.com> - 1.1.9-1
|
||||||
|
- Fix JSON generation for RHV provider registration
|
||||||
|
- Add default values for metrics variables
|
||||||
|
- Create appliance disk names based on it's type
|
||||||
|
- Add embedded ansible as a default service to example
|
||||||
|
- Disable cloud-init service after deployment
|
||||||
|
- Don't hardcode /tmp/ovirt_image_path
|
||||||
|
- Update to Gaprindashvili-3
|
||||||
|
- Add root user to cfme appliance inventory
|
||||||
|
- Add support to disable/enable roles on the appliance.
|
||||||
|
- Add support to set company name.
|
||||||
|
- Add support for log and tmp disks.
|
||||||
|
- Add support for different passwords: application, database and operating system.
|
||||||
|
|
||||||
|
* Thu May 3 2018 Ondra Machacek <omachace@redhat.com> - 1.1.8-1
|
||||||
|
- Use no_log=true for uri module.
|
||||||
|
|
||||||
|
* Tue Apr 10 2018 Ondra Machacek <omachace@redhat.com> - 1.1.7-1
|
||||||
|
- Require Ansible 2.5.
|
||||||
|
- Initialize CFME with default value.
|
||||||
|
- Update defaults to use Gaprindashvili-2.
|
||||||
|
|
||||||
|
* Thu Mar 1 2018 Ondra Machacek <omachace@redhat.com> - 1.1.6-1
|
||||||
|
- Ensure VM is running before checking ManageIQ API.
|
||||||
|
- Add variable for C&U Metrics Database Name.
|
||||||
|
- Pass if provider already exists.
|
||||||
|
- Verify API connectivity before fetching image.
|
||||||
|
- Move to the Gaprindashvili release of ManageIQ.
|
||||||
|
|
||||||
|
* Wed Jan 17 2018 Ondra Machacek <omachace@redhat.com> - 1.1.5-1
|
||||||
|
- Support RHV credentials for Ansible Tower/AWX.
|
||||||
|
|
||||||
|
* Tue Dec 12 2017 Ondra Machacek <omachace@redhat.com> - 1.1.4-1
|
||||||
|
- Add missing templates/ directory.
|
||||||
|
|
||||||
|
* Mon Dec 04 2017 Ondra Machacek <omachace@redhat.com> - 1.1.3-1
|
||||||
|
- Add %pretrans scriplet to remove legacy role name.
|
||||||
|
|
||||||
|
* Wed Nov 29 2017 Ondra Machacek <omachace@redhat.com> - 1.1.2-1
|
||||||
|
- Rename prefix ovirt. to oVirt. to sync with galaxy
|
||||||
|
|
||||||
|
* Thu Nov 16 2017 Ondra Machacek <omachace@redhat.com> - 1.1.0-1
|
||||||
|
- Initial release
|
||||||
15
roles/ovirt.manageiq/tasks/cfme_add_disk.yml
Normal file
15
roles/ovirt.manageiq/tasks/cfme_add_disk.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
- name: Add {{ item }} disk for CFME
|
||||||
|
ovirt_disk:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
name: "{{ miq_vm_disks[item].name | default(miq_vm_name ~ '_' ~ item) }}"
|
||||||
|
vm_name: "{{ miq_vm_name }}"
|
||||||
|
interface: "{{ miq_vm_disks[item].interface | default('virtio_scsi') }}"
|
||||||
|
size: "{{ miq_vm_disks[item].size | default(omit) }}"
|
||||||
|
format: "{{ miq_vm_disks[item].format | default(omit) }}"
|
||||||
|
timeout: "{{ miq_vm_disks[item].timeout | default(omit) }}"
|
||||||
|
storage_domain: "{{ miq_vm_disks[item].storage | default(disk_storage_domain.name if disk_storage_domain is defined else miq_vm_disk_storage) }}"
|
||||||
|
|
||||||
|
- name: Add {{ item }} disk to CloudForms initialization command
|
||||||
|
no_log: "{{ not miq_debug_create }}"
|
||||||
|
set_fact:
|
||||||
|
miq_init_cmd2: "{{ miq_init_cmd2 }} {{ miq_init_cmd_options.disks[item] }} {{ miq_vm_disks_devices[item] }}"
|
||||||
73
roles/ovirt.manageiq/tasks/cfme_identify_disk_device.yml
Normal file
73
roles/ovirt.manageiq/tasks/cfme_identify_disk_device.yml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
- name: Set database disk to /dev/vdb if disk interface is virtio
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_db_device: /dev/vdb
|
||||||
|
when: "miq_vm_disks.database.interface == 'virtio'"
|
||||||
|
|
||||||
|
- name: Set database disk to /dev/sdb if disk interface is virtio_scsi
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_db_device: /dev/sdb
|
||||||
|
when: "miq_vm_disks.database.interface == 'virtio_scsi'"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
miq_vm_disks_devices:
|
||||||
|
database: "{{ miq_vm_disks_db_device }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
|
||||||
|
- name: Set log disk to /dev/vdc if disk interface is virtio
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_log_device: /dev/vdc
|
||||||
|
when: "miq_vm_disks.log.interface == 'virtio'"
|
||||||
|
|
||||||
|
- name: Set log disk to /dev/sdc if disk interface is virtio_scsi
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_log_device: /dev/sdc
|
||||||
|
when: "miq_vm_disks.log.interface == 'virtio_scsi'"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
miq_vm_disks_log_device_dict:
|
||||||
|
log: "{{ miq_vm_disks_log_device }}"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
miq_vm_disks_devices: "{{ miq_vm_disks_devices | combine(miq_vm_disks_log_device_dict) }}"
|
||||||
|
|
||||||
|
when: "'log' in miq_vm_disks"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
|
||||||
|
- block:
|
||||||
|
|
||||||
|
- name: Set tmp disk to /dev/vdc if disk interface is virtio
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_tmp_device: /dev/vdc
|
||||||
|
when: "miq_vm_disks.tmp.interface == 'virtio'"
|
||||||
|
|
||||||
|
- name: Set tmp disk to /dev/sdc if disk interface is virtio_scsi
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_tmp_device: /dev/sdc
|
||||||
|
when: "miq_vm_disks.tmp.interface == 'virtio_scsi'"
|
||||||
|
|
||||||
|
when: "'log' not in miq_vm_disks"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
|
||||||
|
- name: Set tmp disk to /dev/vdd if disk interface is virtio
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_tmp_device: /dev/vdd
|
||||||
|
when: "miq_vm_disks.tmp.interface == 'virtio'"
|
||||||
|
|
||||||
|
- name: Set tmp disk to /dev/sdd if disk interface is virtio_scsi
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disks_tmp_device: /dev/sdd
|
||||||
|
when: "miq_vm_disks.tmp.interface == 'virtio_scsi'"
|
||||||
|
|
||||||
|
when: "'log' in miq_vm_disks"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
miq_vm_disks_tmp_device_dict:
|
||||||
|
tmp: "{{ miq_vm_disks_tmp_device }}"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
miq_vm_disks_devices: "{{ miq_vm_disks_devices | combine(miq_vm_disks_tmp_device_dict) }}"
|
||||||
|
|
||||||
|
when: "'tmp' in miq_vm_disks"
|
||||||
84
roles/ovirt.manageiq/tasks/deploy_qcow2.yml
Normal file
84
roles/ovirt.manageiq/tasks/deploy_qcow2.yml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
- name: Check if {{ miq_image_path }} is directory
|
||||||
|
stat:
|
||||||
|
path: "{{ miq_image_path }}"
|
||||||
|
register: image_path_st
|
||||||
|
|
||||||
|
- name: Download the qcow image
|
||||||
|
get_url:
|
||||||
|
url: "{{ miq_qcow_url }}"
|
||||||
|
dest: "{{ image_path_st.stat.isdir | ternary( miq_image_path~'/'~miq_qcow_url.rpartition('/')[-1], miq_image_path) | regex_replace('//', '/') }}"
|
||||||
|
checksum: "{{ miq_image_checksum | default(omit) }}"
|
||||||
|
register: downloaded_file
|
||||||
|
|
||||||
|
- name: Check file type
|
||||||
|
command: "/usr/bin/file {{ downloaded_file.dest | quote }}"
|
||||||
|
changed_when: false
|
||||||
|
register: filetype
|
||||||
|
|
||||||
|
- name: Fail if image is not qcow
|
||||||
|
fail:
|
||||||
|
msg: "The downloaded file is not a valid QCOW file."
|
||||||
|
when: '"QCOW" not in filetype.stdout'
|
||||||
|
|
||||||
|
- name: Calculate image size in GiB
|
||||||
|
set_fact:
|
||||||
|
miq_image_size_gib: "{{ filetype.stdout_lines[0].split()[5] | int // 2**30 }}"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Find default disk size for miq disk:
|
||||||
|
#
|
||||||
|
- block:
|
||||||
|
- name: Extract integer from miq_vm_disk_size
|
||||||
|
set_fact:
|
||||||
|
miq_vm_disk_size_gib: "{{ miq_vm_disk_size | regex_replace('GiB$') }}"
|
||||||
|
|
||||||
|
- name: Fail if miq_vm_disk_size is less than qcow size
|
||||||
|
fail:
|
||||||
|
msg: "Setting a disk size ({{ miq_vm_disk_size }}) lower than the image size ({{ miq_image_size_gib }}GiB) may result in disk corruption."
|
||||||
|
when: "miq_vm_disk_size_gib < miq_image_size_gib"
|
||||||
|
when: "miq_vm_disk_size is defined"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Find default data storage domain for Miq disk:
|
||||||
|
#
|
||||||
|
- block:
|
||||||
|
- name: Fetch storages
|
||||||
|
ovirt_storage_domain_facts:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
pattern: "Clusters.name={{ miq_vm_cluster }} and status=active"
|
||||||
|
|
||||||
|
- name: Find data domain
|
||||||
|
set_fact:
|
||||||
|
disk_storage_domain: "{{ ovirt_storage_domains | json_query(the_query) | list | first }}"
|
||||||
|
vars:
|
||||||
|
the_query: "[?type=='data']"
|
||||||
|
when: miq_vm_disk_storage is undefined
|
||||||
|
|
||||||
|
- name: Check if VM already exists
|
||||||
|
ovirt_vm_facts:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
pattern: "name={{ miq_vm_name }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Deploy the qcow image to oVirt engine
|
||||||
|
ovirt_disk:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
name: "{{ miq_vm_disk_name | default(miq_vm_name) }}"
|
||||||
|
interface: "{{ miq_vm_disk_interface }}"
|
||||||
|
size: "{{ miq_vm_disk_size | default(miq_image_size_gib + 'GiB') }}"
|
||||||
|
format: "{{ miq_vm_disk_format }}"
|
||||||
|
image_path: "{{ downloaded_file.dest }}"
|
||||||
|
storage_domain: "{{ disk_storage_domain.name if disk_storage_domain is defined else miq_vm_disk_storage }}"
|
||||||
|
force: "{{ ovirt_vms | length == 0 }}"
|
||||||
|
register: ovirt_disk
|
||||||
|
|
||||||
|
rescue:
|
||||||
|
- name: Remove failed disk
|
||||||
|
ovirt_disk:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
state: absent
|
||||||
|
name: "{{ miq_vm_disk_name | default(miq_vm_name) }}"
|
||||||
|
|
||||||
|
- name: Set miq_disk_deploy_failed
|
||||||
|
set_fact:
|
||||||
|
miq_disk_deploy_failed: true
|
||||||
57
roles/ovirt.manageiq/tasks/init_cfme.yml
Normal file
57
roles/ovirt.manageiq/tasks/init_cfme.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
- name: Add host alias of appliance
|
||||||
|
no_log: "{{ not miq_debug_create }}"
|
||||||
|
add_host:
|
||||||
|
hostname: "{{ miq_ip_addr }}"
|
||||||
|
ansible_host: "{{ miq_ip_addr }}"
|
||||||
|
ansible_user: root
|
||||||
|
ansible_password: smartvm
|
||||||
|
ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Wait for SSH port of appliance
|
||||||
|
wait_for:
|
||||||
|
host: "{{ miq_ip_addr }}"
|
||||||
|
port: 22
|
||||||
|
delay: 10
|
||||||
|
|
||||||
|
- name: Fetch info about appliance
|
||||||
|
command: "rpm -qi cfme"
|
||||||
|
args:
|
||||||
|
warn: no
|
||||||
|
register: cfme_rpm
|
||||||
|
ignore_errors: yes
|
||||||
|
changed_when: false
|
||||||
|
delegate_to: "{{ miq_ip_addr }}"
|
||||||
|
|
||||||
|
- name: Check if ManageIQ/CloudForms was initilized
|
||||||
|
no_log: "{{ not miq_debug_create }}"
|
||||||
|
uri:
|
||||||
|
url: "https://{{ miq_ip_addr }}/api/"
|
||||||
|
validate_certs: no
|
||||||
|
user: "{{ miq_app_username }}"
|
||||||
|
password: smartvm
|
||||||
|
register: init_miq_vm
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Set region id
|
||||||
|
set_fact:
|
||||||
|
miq_region_id: "{{ miq_region|int * 1000000000000 + 1 }}"
|
||||||
|
|
||||||
|
- name: Initialize CloudForms
|
||||||
|
command: "{{ miq_init_cmd2 }}"
|
||||||
|
delegate_to: "{{ miq_ip_addr }}"
|
||||||
|
when: "init_miq_vm.failed"
|
||||||
|
|
||||||
|
when: "cfme_rpm.rc == 0 and init_miq_vm.failed"
|
||||||
|
|
||||||
|
- name: Set root password of appliance
|
||||||
|
no_log: "{{ not miq_debug_create }}"
|
||||||
|
shell: echo '{{ miq_vm_root_password }}' | passwd --stdin root
|
||||||
|
delegate_to: "{{ miq_ip_addr }}"
|
||||||
|
|
||||||
|
- name: Disable cloud-init service
|
||||||
|
service:
|
||||||
|
enabled: no
|
||||||
|
name: cloud-init
|
||||||
|
delegate_to: "{{ miq_ip_addr }}"
|
||||||
108
roles/ovirt.manageiq/tasks/main.yml
Normal file
108
roles/ovirt.manageiq/tasks/main.yml
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
---
|
||||||
|
- block:
|
||||||
|
## Initialize authentication parameters:
|
||||||
|
- set_fact:
|
||||||
|
engine_url: "{{ 'https://' ~engine_fqdn | default(lookup('env', 'OVIRT_HOSTNAME')) ~ '/ovirt-engine/api' }}"
|
||||||
|
when: engine_fqdn is defined or lookup('env', 'OVIRT_HOSTNAME')
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
engine_user: "{{ engine_user | default(lookup('env', 'OVIRT_USERNAME')) }}"
|
||||||
|
engine_password: "{{ engine_password | default(lookup('env', 'OVIRT_PASSWORD')) }}"
|
||||||
|
engine_url: "{{ engine_url | default(lookup('env', 'OVIRT_URL')) }}"
|
||||||
|
engine_cafile: "{{ engine_cafile | default(lookup('env', 'OVIRT_CAFILE')) }}"
|
||||||
|
|
||||||
|
- name: Login to oVirt engine
|
||||||
|
ovirt_auth:
|
||||||
|
username: "{{ engine_user }}"
|
||||||
|
password: "{{ engine_password }}"
|
||||||
|
url: "{{ engine_url }}"
|
||||||
|
ca_file: "{{ engine_cafile }}"
|
||||||
|
insecure: "{{ engine_cafile == '' }}"
|
||||||
|
when: ovirt_auth is undefined or not ovirt_auth
|
||||||
|
register: loggedin
|
||||||
|
tags:
|
||||||
|
- always
|
||||||
|
|
||||||
|
- name: Deploy qcow disk
|
||||||
|
include_tasks: deploy_qcow2.yml
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Create ManageIQ virtual machine
|
||||||
|
ovirt_vm:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
state: present
|
||||||
|
name: "{{ miq_vm_name }}"
|
||||||
|
cluster: "{{ miq_vm_cluster }}"
|
||||||
|
memory: "{{ miq_vm_memory }}"
|
||||||
|
memory_max: "{{ miq_vm_memory_max | default(omit) }}"
|
||||||
|
memory_guaranteed: "{{ miq_vm_memory_guaranteed | default(omit) }}"
|
||||||
|
cpu_cores: "{{ miq_vm_cpu }}"
|
||||||
|
cpu_shares: "{{ miq_vm_cpu_shares | default(omit) }}"
|
||||||
|
cpu_sockets: "{{ miq_vm_cpu_sockets | default(omit) }}"
|
||||||
|
cpu_threads: "{{ miq_vm_cpu_threads | default(omit) }}"
|
||||||
|
operating_system: "{{ miq_vm_os }}"
|
||||||
|
high_availability: "{{ miq_vm_high_availability }}"
|
||||||
|
high_availability_priority: "{{ miq_vm_high_availability_priority }}"
|
||||||
|
delete_protected: "{{ miq_vm_delete_protected }}"
|
||||||
|
type: server
|
||||||
|
disks:
|
||||||
|
- id: "{{ ovirt_disk.id }}"
|
||||||
|
bootable: true
|
||||||
|
nics: "{{ miq_vm_nics }}"
|
||||||
|
register: create_vm
|
||||||
|
|
||||||
|
- name: Duplicate miq_init_cmd variable to override it
|
||||||
|
set_fact:
|
||||||
|
miq_init_cmd2: "{{ miq_init_cmd }}"
|
||||||
|
|
||||||
|
- include_tasks: cfme_identify_disk_device.yml
|
||||||
|
|
||||||
|
- include_tasks: cfme_add_disk.yml
|
||||||
|
when: "item in miq_vm_disks"
|
||||||
|
with_items: "{{ miq_vm_disks_types }}"
|
||||||
|
|
||||||
|
- name: Ensure virtual machine is running
|
||||||
|
ovirt_vm:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
state: running
|
||||||
|
name: "{{ miq_vm_name }}"
|
||||||
|
cloud_init: "{{ miq_vm_cloud_init | default(omit) }}"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
ip_cond: "ovirt_vms | ovirtvmip{{ miq_wait_for_ip_version }} | length > 0"
|
||||||
|
|
||||||
|
- name: Wait for VM IP
|
||||||
|
ovirt_vm_facts:
|
||||||
|
auth: "{{ ovirt_auth }}"
|
||||||
|
pattern: "name={{ miq_vm_name }}"
|
||||||
|
fetch_nested: true
|
||||||
|
nested_attributes: ips
|
||||||
|
until: "ip_cond"
|
||||||
|
retries: 10
|
||||||
|
delay: 10
|
||||||
|
|
||||||
|
- name: ManageIQ host IPv4 address
|
||||||
|
set_fact:
|
||||||
|
miq_ip_addr: "{{ ovirt_vms | ovirtvmipv4 }}"
|
||||||
|
when: miq_wait_for_ip_version == 'v4'
|
||||||
|
|
||||||
|
- name: ManageIQ host IPv6 address
|
||||||
|
set_fact:
|
||||||
|
miq_ip_addr: "{{ ovirt_vms | ovirtvmipv6 }}"
|
||||||
|
when: miq_wait_for_ip_version == 'v6'
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- include: init_cfme.yml
|
||||||
|
- include: wait_for_api.yml
|
||||||
|
|
||||||
|
when: "miq_initialize"
|
||||||
|
when: "not miq_disk_deploy_failed"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Logout from oVirt engine
|
||||||
|
ovirt_auth:
|
||||||
|
state: absent
|
||||||
|
ovirt_auth: "{{ ovirt_auth }}"
|
||||||
|
when: not loggedin.skipped | default(false)
|
||||||
|
tags:
|
||||||
|
- always
|
||||||
33
roles/ovirt.manageiq/tasks/manage_appliance_roles.yml
Normal file
33
roles/ovirt.manageiq/tasks/manage_appliance_roles.yml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
- name: Get the list of enabled roles
|
||||||
|
uri:
|
||||||
|
url: "https://{{ miq_ip_addr }}/api/servers/{{ miq_region_id }}/settings"
|
||||||
|
user: "{{ miq_app_username }}"
|
||||||
|
password: "{{ miq_app_password }}"
|
||||||
|
method: GET
|
||||||
|
validate_certs: no
|
||||||
|
register: miq_active_roles_json
|
||||||
|
|
||||||
|
- name: Extracting the roles from the JSON output
|
||||||
|
set_fact:
|
||||||
|
miq_active_roles: "{{ miq_active_roles_json.json.server.role.split(',') }}"
|
||||||
|
|
||||||
|
- name: Remove roles from the list of active roles
|
||||||
|
set_fact:
|
||||||
|
miq_active_roles: "{{ miq_active_roles | difference(miq_disabled_roles) }}"
|
||||||
|
|
||||||
|
- name: Add extra roles to list of active roles
|
||||||
|
set_fact:
|
||||||
|
miq_active_roles: "{{ miq_active_roles | union(miq_enabled_roles) }}"
|
||||||
|
|
||||||
|
- name: Update list of active roles
|
||||||
|
uri:
|
||||||
|
url: https://{{ miq_ip_addr }}/api/servers/{{ miq_region_id }}/settings
|
||||||
|
user: "{{ miq_app_username }}"
|
||||||
|
password: "{{ miq_app_password }}"
|
||||||
|
method: PATCH
|
||||||
|
validate_certs: no
|
||||||
|
body_format: json
|
||||||
|
body:
|
||||||
|
server:
|
||||||
|
role: "{{ miq_active_roles | join(',') }}"
|
||||||
68
roles/ovirt.manageiq/tasks/wait_for_api.yml
Normal file
68
roles/ovirt.manageiq/tasks/wait_for_api.yml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
- name: Wait for ManageIQ/CloudForms API
|
||||||
|
no_log: "{{ not miq_debug_create }}"
|
||||||
|
uri:
|
||||||
|
url: "https://{{ miq_ip_addr }}/api/"
|
||||||
|
validate_certs: no
|
||||||
|
user: "{{ miq_app_username }}"
|
||||||
|
password: smartvm
|
||||||
|
register: miq_vm
|
||||||
|
until: "miq_vm.status == 200"
|
||||||
|
retries: 50
|
||||||
|
delay: 20
|
||||||
|
|
||||||
|
- name: Set application admin password
|
||||||
|
no_log: "{{ not miq_debug_create }}"
|
||||||
|
uri:
|
||||||
|
url: "https://{{ miq_ip_addr }}/api/users/{{ miq_region_id }}"
|
||||||
|
validate_certs: no
|
||||||
|
method: POST
|
||||||
|
user: "{{ miq_app_username }}"
|
||||||
|
password: smartvm
|
||||||
|
force_basic_auth: yes
|
||||||
|
body_format: json
|
||||||
|
body:
|
||||||
|
action: "edit"
|
||||||
|
resource:
|
||||||
|
password: "{{ miq_app_password | string }}"
|
||||||
|
register: miq_admin_password
|
||||||
|
changed_when: "miq_admin_password.status == 201 or miq_admin_password.status == 200"
|
||||||
|
failed_when:
|
||||||
|
- "miq_admin_password.json is defined and 'error' in miq_admin_password.json"
|
||||||
|
|
||||||
|
- name: Update ManageIQ company name
|
||||||
|
uri:
|
||||||
|
url: "https://{{ miq_ip_addr }}/api/servers/{{ miq_region_id }}/settings"
|
||||||
|
user: "{{ miq_app_username }}"
|
||||||
|
password: "{{ miq_app_password }}"
|
||||||
|
method: PATCH
|
||||||
|
validate_certs: no
|
||||||
|
body_format: json
|
||||||
|
body:
|
||||||
|
server:
|
||||||
|
company: "{{ miq_company }}"
|
||||||
|
register: miq_update_company
|
||||||
|
changed_when: "miq_update_company.status == 201 or miq_update_company.status == 200"
|
||||||
|
failed_when:
|
||||||
|
- "miq_update_company.json is defined and 'error' in miq_update_company.json"
|
||||||
|
|
||||||
|
- include_tasks: manage_appliance_roles.yml
|
||||||
|
|
||||||
|
- name: Add oVirt/RHV provider to ManageIQ/CloudForms
|
||||||
|
no_log: "{{ not miq_debug_create }}"
|
||||||
|
uri:
|
||||||
|
url: "https://{{ miq_ip_addr }}/api/providers"
|
||||||
|
validate_certs: no
|
||||||
|
method: POST
|
||||||
|
user: "{{ miq_app_username }}"
|
||||||
|
password: "{{ miq_app_password }}"
|
||||||
|
body: "{{ lookup('template', 'add_rhv_provider.j2') }}"
|
||||||
|
force_basic_auth: yes
|
||||||
|
body_format: json
|
||||||
|
register: miq_rhv_provider
|
||||||
|
changed_when: "miq_rhv_provider.status == 201 or miq_rhv_provider.status == 200"
|
||||||
|
failed_when:
|
||||||
|
- "miq_rhv_provider.json is defined and 'error' in miq_rhv_provider.json"
|
||||||
|
- "miq_rhv_provider.json.error.message is defined and 'has already been taken' not in miq_rhv_provider.json.error.message"
|
||||||
|
# FIXME: If provider already exists with different name, don't fail, but we should change the name
|
||||||
|
# when there will exist any ansible module for managing providers:
|
||||||
|
- "miq_rhv_provider.json.error.message is defined and 'Host Name has to be unique per provider type' not in miq_rhv_provider.json.error.message"
|
||||||
43
roles/ovirt.manageiq/templates/add_rhv_provider.j2
Normal file
43
roles/ovirt.manageiq/templates/add_rhv_provider.j2
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"type": "ManageIQ::Providers::Redhat::InfraManager",
|
||||||
|
"name": "{{ miq_rhv_provider_name }}",
|
||||||
|
"connection_configurations": [{
|
||||||
|
"endpoint": {
|
||||||
|
"role": "default",
|
||||||
|
{% if engine_fqdn is defined %}
|
||||||
|
"hostname": "{{ engine_fqdn.split(':')[0] }}",
|
||||||
|
{% if engine_fqdn.split(':') | length > 1 %}
|
||||||
|
"port": "{{ engine_fqdn.split(':')[1] }}",
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
"hostname": "{{ engine_url | urlsplit('hostname') }}",
|
||||||
|
{% if engine_url | urlsplit('port') != "" %}
|
||||||
|
"port": "{{ engine_url | urlsplit('port') }}",
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
"verify_ssl": {{ engine_cafile != '' }},
|
||||||
|
{% if engine_cafile != '' %}
|
||||||
|
"certificate_authority": {{ lookup('file', engine_cafile) | to_json }}
|
||||||
|
{% endif %}
|
||||||
|
},
|
||||||
|
"authentication": {
|
||||||
|
"userid": "{{ engine_user }}",
|
||||||
|
"password": "{{ engine_password }}"
|
||||||
|
}
|
||||||
|
}{% if metrics_fqdn is defined %},{% endif %}
|
||||||
|
{% if metrics_fqdn is defined %}
|
||||||
|
{
|
||||||
|
"endpoint": {
|
||||||
|
"role": "metrics",
|
||||||
|
"path": "{{ metrics_db_name }}",
|
||||||
|
"hostname": "{{ metrics_fqdn }}",
|
||||||
|
"port": "{{ metrics_port }}"
|
||||||
|
},
|
||||||
|
"authentication": {
|
||||||
|
"userid": "{{ metrics_user }}",
|
||||||
|
"password": "{{ metrics_password }}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
]
|
||||||
|
}
|
||||||
11
roles/ovirt.manageiq/tox.ini
Normal file
11
roles/ovirt.manageiq/tox.ini
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[tox]
|
||||||
|
skipsdist=True
|
||||||
|
envlist =
|
||||||
|
py27-{yamllint,ansible_syntax,generate_validation}
|
||||||
|
skip_missing_interpreters=True
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
skip_install=True
|
||||||
|
|
||||||
|
commands =
|
||||||
|
yamllint: yamllint examples/
|
||||||
10
roles/ovirt.manageiq/vars/main.yml
Normal file
10
roles/ovirt.manageiq/vars/main.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
miq_vm_disks_types:
|
||||||
|
- database
|
||||||
|
- log
|
||||||
|
- tmp
|
||||||
|
miq_init_cmd_options:
|
||||||
|
disks:
|
||||||
|
database: "-b"
|
||||||
|
log: "-l"
|
||||||
|
tmp: "-t"
|
||||||
@@ -183,6 +183,9 @@
|
|||||||
name: sos
|
name: sos
|
||||||
state: latest
|
state: latest
|
||||||
|
|
||||||
|
# TODO: set this in Administer -> Settings -> Puppet Puppet out of sync disabled = Yes
|
||||||
|
# Description: Disable host configuration status turning to out of sync for Puppet after report does not arrive within configured interval
|
||||||
|
|
||||||
# TODO: Make this work
|
# TODO: Make this work
|
||||||
# For now:
|
# For now:
|
||||||
# hammer user-group create --admin yes --name satellite_admins
|
# hammer user-group create --admin yes --name satellite_admins
|
||||||
|
|||||||
Reference in New Issue
Block a user