diff options
Diffstat (limited to 'roles')
33 files changed, 1156 insertions, 195 deletions
diff --git a/roles/calico/tasks/main.yml b/roles/calico/tasks/main.yml index 0e3863304..bbc6edd48 100644 --- a/roles/calico/tasks/main.yml +++ b/roles/calico/tasks/main.yml @@ -14,7 +14,6 @@ vars: etcd_cert_prefix: calico.etcd- etcd_cert_config_dir: "{{ openshift.common.config_base }}/calico" - embedded_etcd: "{{ hostvars[groups.oo_first_master.0].openshift.master.embedded_etcd }}" etcd_ca_host: "{{ groups.oo_etcd_to_config.0 }}" etcd_cert_subdir: "openshift-calico-{{ openshift.common.hostname }}" diff --git a/roles/etcd/meta/main.yml b/roles/etcd/meta/main.yml index 879ca4f4e..f2e1fc310 100644 --- a/roles/etcd/meta/main.yml +++ b/roles/etcd/meta/main.yml @@ -19,3 +19,4 @@ dependencies: - role: lib_openshift - role: lib_os_firewall - role: lib_utils +- role: openshift_facts diff --git a/roles/flannel/defaults/main.yaml b/roles/flannel/defaults/main.yaml index 488b6b0bc..2e4a0dc39 100644 --- a/roles/flannel/defaults/main.yaml +++ b/roles/flannel/defaults/main.yaml @@ -2,8 +2,8 @@ flannel_interface: "{{ ansible_default_ipv4.interface }}" flannel_etcd_key: /openshift.com/network etcd_hosts: "{{ etcd_urls }}" -etcd_peer_ca_file: "{{ openshift.common.config_base }}/node/{{ 'ca' if (embedded_etcd | bool) else 'flannel.etcd-ca' }}.crt" -etcd_peer_cert_file: "{{ openshift.common.config_base }}/node/{{ 'system:node:' + openshift.common.hostname if (embedded_etcd | bool) else 'flannel.etcd-client' }}.crt" -etcd_peer_key_file: "{{ openshift.common.config_base }}/node/{{ 'system:node:' + openshift.common.hostname if (embedded_etcd | bool) else 'flannel.etcd-client' }}.key" +etcd_peer_ca_file: "{{ openshift.common.config_base }}/node/flannel.etcd-ca.crt" +etcd_peer_cert_file: "{{ openshift.common.config_base }}/node/flannel.etcd-client.crt" +etcd_peer_key_file: "{{ openshift.common.config_base }}/node/flannel.etcd-client.key" openshift_docker_service_name: "{{ 'container-engine' if (openshift_docker_use_system_container | default(False)) else 'docker' }}" diff --git a/roles/flannel_register/defaults/main.yaml b/roles/flannel_register/defaults/main.yaml index 1d0f5df6a..cd11fd9ff 100644 --- a/roles/flannel_register/defaults/main.yaml +++ b/roles/flannel_register/defaults/main.yaml @@ -4,6 +4,6 @@ flannel_subnet_len: "{{ 32 - (openshift.master.sdn_host_subnet_length | int) }}" flannel_etcd_key: /openshift.com/network etcd_hosts: "{{ etcd_urls }}" etcd_conf_dir: "{{ openshift.common.config_base }}/master" -etcd_peer_ca_file: "{{ etcd_conf_dir + '/ca.crt' if (openshift.master.embedded_etcd | bool) else etcd_conf_dir + '/master.etcd-ca.crt' }}" +etcd_peer_ca_file: "{{ etcd_conf_dir + '/master.etcd-ca.crt' }}" etcd_peer_cert_file: "{{ etcd_conf_dir }}/master.etcd-client.crt" etcd_peer_key_file: "{{ etcd_conf_dir }}/master.etcd-client.key" diff --git a/roles/lib_utils/library/oo_ec2_group.py b/roles/lib_utils/library/oo_ec2_group.py new file mode 100644 index 000000000..615021ac5 --- /dev/null +++ b/roles/lib_utils/library/oo_ec2_group.py @@ -0,0 +1,903 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# pylint: skip-file +# flake8: noqa + +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['stableinterface'], + 'supported_by': 'core'} + +DOCUMENTATION = ''' +--- +module: ec2_group +author: "Andrew de Quincey (@adq)" +version_added: "1.3" +requirements: [ boto3 ] +short_description: maintain an ec2 VPC security group. +description: + - maintains ec2 security groups. This module has a dependency on python-boto >= 2.5 +options: + name: + description: + - Name of the security group. + - One of and only one of I(name) or I(group_id) is required. + - Required if I(state=present). + required: false + group_id: + description: + - Id of group to delete (works only with absent). + - One of and only one of I(name) or I(group_id) is required. + required: false + version_added: "2.4" + description: + description: + - Description of the security group. Required when C(state) is C(present). + required: false + vpc_id: + description: + - ID of the VPC to create the group in. + required: false + rules: + description: + - List of firewall inbound rules to enforce in this group (see example). If none are supplied, + no inbound rules will be enabled. Rules list may include its own name in `group_name`. + This allows idempotent loopback additions (e.g. allow group to access itself). + Rule sources list support was added in version 2.4. This allows to define multiple sources per + source type as well as multiple source types per rule. Prior to 2.4 an individual source is allowed. + required: false + rules_egress: + description: + - List of firewall outbound rules to enforce in this group (see example). If none are supplied, + a default all-out rule is assumed. If an empty list is supplied, no outbound rules will be enabled. + Rule Egress sources list support was added in version 2.4. + required: false + version_added: "1.6" + state: + version_added: "1.4" + description: + - Create or delete a security group + required: false + default: 'present' + choices: [ "present", "absent" ] + aliases: [] + purge_rules: + version_added: "1.8" + description: + - Purge existing rules on security group that are not found in rules + required: false + default: 'true' + aliases: [] + purge_rules_egress: + version_added: "1.8" + description: + - Purge existing rules_egress on security group that are not found in rules_egress + required: false + default: 'true' + aliases: [] + tags: + version_added: "2.4" + description: + - A dictionary of one or more tags to assign to the security group. + required: false + purge_tags: + version_added: "2.4" + description: + - If yes, existing tags will be purged from the resource to match exactly what is defined by I(tags) parameter. If the I(tags) parameter is not set then + tags will not be modified. + required: false + default: yes + choices: [ 'yes', 'no' ] + +extends_documentation_fragment: + - aws + - ec2 + +notes: + - If a rule declares a group_name and that group doesn't exist, it will be + automatically created. In that case, group_desc should be provided as well. + The module will refuse to create a depended-on group without a description. +''' + +EXAMPLES = ''' +- name: example ec2 group + ec2_group: + name: example + description: an example EC2 group + vpc_id: 12345 + region: eu-west-1 + aws_secret_key: SECRET + aws_access_key: ACCESS + rules: + - proto: tcp + from_port: 80 + to_port: 80 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 22 + to_port: 22 + cidr_ip: 10.0.0.0/8 + - proto: tcp + from_port: 443 + to_port: 443 + group_id: amazon-elb/sg-87654321/amazon-elb-sg + - proto: tcp + from_port: 3306 + to_port: 3306 + group_id: 123412341234/sg-87654321/exact-name-of-sg + - proto: udp + from_port: 10050 + to_port: 10050 + cidr_ip: 10.0.0.0/8 + - proto: udp + from_port: 10051 + to_port: 10051 + group_id: sg-12345678 + - proto: icmp + from_port: 8 # icmp type, -1 = any type + to_port: -1 # icmp subtype, -1 = any subtype + cidr_ip: 10.0.0.0/8 + - proto: all + # the containing group name may be specified here + group_name: example + rules_egress: + - proto: tcp + from_port: 80 + to_port: 80 + cidr_ip: 0.0.0.0/0 + cidr_ipv6: 64:ff9b::/96 + group_name: example-other + # description to use if example-other needs to be created + group_desc: other example EC2 group + +- name: example2 ec2 group + ec2_group: + name: example2 + description: an example2 EC2 group + vpc_id: 12345 + region: eu-west-1 + rules: + # 'ports' rule keyword was introduced in version 2.4. It accepts a single port value or a list of values including ranges (from_port-to_port). + - proto: tcp + ports: 22 + group_name: example-vpn + - proto: tcp + ports: + - 80 + - 443 + - 8080-8099 + cidr_ip: 0.0.0.0/0 + # Rule sources list support was added in version 2.4. This allows to define multiple sources per source type as well as multiple source types per rule. + - proto: tcp + ports: + - 6379 + - 26379 + group_name: + - example-vpn + - example-redis + - proto: tcp + ports: 5665 + group_name: example-vpn + cidr_ip: + - 172.16.1.0/24 + - 172.16.17.0/24 + cidr_ipv6: + - 2607:F8B0::/32 + - 64:ff9b::/96 + group_id: + - sg-edcd9784 + +- name: "Delete group by its id" + ec2_group: + group_id: sg-33b4ee5b + state: absent +''' + +RETURN = ''' +group_name: + description: Security group name + sample: My Security Group + type: string + returned: on create/update +group_id: + description: Security group id + sample: sg-abcd1234 + type: string + returned: on create/update +description: + description: Description of security group + sample: My Security Group + type: string + returned: on create/update +tags: + description: Tags associated with the security group + sample: + Name: My Security Group + Purpose: protecting stuff + type: dict + returned: on create/update +vpc_id: + description: ID of VPC to which the security group belongs + sample: vpc-abcd1234 + type: string + returned: on create/update +ip_permissions: + description: Inbound rules associated with the security group. + sample: + - from_port: 8182 + ip_protocol: tcp + ip_ranges: + - cidr_ip: "1.1.1.1/32" + ipv6_ranges: [] + prefix_list_ids: [] + to_port: 8182 + user_id_group_pairs: [] + type: list + returned: on create/update +ip_permissions_egress: + description: Outbound rules associated with the security group. + sample: + - ip_protocol: -1 + ip_ranges: + - cidr_ip: "0.0.0.0/0" + ipv6_ranges: [] + prefix_list_ids: [] + user_id_group_pairs: [] + type: list + returned: on create/update +owner_id: + description: AWS Account ID of the security group + sample: 123456789012 + type: int + returned: on create/update +''' + +import json +import re +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ec2 import boto3_conn +from ansible.module_utils.ec2 import get_aws_connection_info +from ansible.module_utils.ec2 import ec2_argument_spec +from ansible.module_utils.ec2 import camel_dict_to_snake_dict +from ansible.module_utils.ec2 import HAS_BOTO3 +from ansible.module_utils.ec2 import boto3_tag_list_to_ansible_dict, ansible_dict_to_boto3_tag_list, compare_aws_tags +from ansible.module_utils.ec2 import AWSRetry +import traceback + +try: + import botocore +except ImportError: + pass # caught by imported HAS_BOTO3 + + +@AWSRetry.backoff(tries=5, delay=5, backoff=2.0) +def get_security_groups_with_backoff(connection, **kwargs): + return connection.describe_security_groups(**kwargs) + + +def deduplicate_rules_args(rules): + """Returns unique rules""" + if rules is None: + return None + return list(dict(zip((json.dumps(r, sort_keys=True) for r in rules), rules)).values()) + + +def make_rule_key(prefix, rule, group_id, cidr_ip): + if 'proto' in rule: + proto, from_port, to_port = [rule.get(x, None) for x in ('proto', 'from_port', 'to_port')] + elif 'IpProtocol' in rule: + proto, from_port, to_port = [rule.get(x, None) for x in ('IpProtocol', 'FromPort', 'ToPort')] + if proto not in ['icmp', 'tcp', 'udp'] and from_port == -1 and to_port == -1: + from_port = 'none' + to_port = 'none' + key = "%s-%s-%s-%s-%s-%s" % (prefix, proto, from_port, to_port, group_id, cidr_ip) + return key.lower().replace('-none', '-None') + + +def add_rules_to_lookup(ipPermissions, group_id, prefix, dict): + for rule in ipPermissions: + for groupGrant in rule.get('UserIdGroupPairs', []): + dict[make_rule_key(prefix, rule, group_id, groupGrant.get('GroupId'))] = (rule, groupGrant) + for ipv4Grants in rule.get('IpRanges', []): + dict[make_rule_key(prefix, rule, group_id, ipv4Grants.get('CidrIp'))] = (rule, ipv4Grants) + for ipv6Grants in rule.get('Ipv6Ranges', []): + dict[make_rule_key(prefix, rule, group_id, ipv6Grants.get('CidrIpv6'))] = (rule, ipv6Grants) + + +def validate_rule(module, rule): + VALID_PARAMS = ('cidr_ip', 'cidr_ipv6', + 'group_id', 'group_name', 'group_desc', + 'proto', 'from_port', 'to_port') + if not isinstance(rule, dict): + module.fail_json(msg='Invalid rule parameter type [%s].' % type(rule)) + for k in rule: + if k not in VALID_PARAMS: + module.fail_json(msg='Invalid rule parameter \'{}\''.format(k)) + + if 'group_id' in rule and 'cidr_ip' in rule: + module.fail_json(msg='Specify group_id OR cidr_ip, not both') + elif 'group_name' in rule and 'cidr_ip' in rule: + module.fail_json(msg='Specify group_name OR cidr_ip, not both') + elif 'group_id' in rule and 'cidr_ipv6' in rule: + module.fail_json(msg="Specify group_id OR cidr_ipv6, not both") + elif 'group_name' in rule and 'cidr_ipv6' in rule: + module.fail_json(msg="Specify group_name OR cidr_ipv6, not both") + elif 'cidr_ip' in rule and 'cidr_ipv6' in rule: + module.fail_json(msg="Specify cidr_ip OR cidr_ipv6, not both") + elif 'group_id' in rule and 'group_name' in rule: + module.fail_json(msg='Specify group_id OR group_name, not both') + + +def get_target_from_rule(module, client, rule, name, group, groups, vpc_id): + """ + Returns tuple of (group_id, ip) after validating rule params. + + rule: Dict describing a rule. + name: Name of the security group being managed. + groups: Dict of all available security groups. + + AWS accepts an ip range or a security group as target of a rule. This + function validate the rule specification and return either a non-None + group_id or a non-None ip range. + """ + + FOREIGN_SECURITY_GROUP_REGEX = '^(\S+)/(sg-\S+)/(\S+)' + group_id = None + group_name = None + ip = None + ipv6 = None + target_group_created = False + + if 'group_id' in rule and 'cidr_ip' in rule: + module.fail_json(msg="Specify group_id OR cidr_ip, not both") + elif 'group_name' in rule and 'cidr_ip' in rule: + module.fail_json(msg="Specify group_name OR cidr_ip, not both") + elif 'group_id' in rule and 'cidr_ipv6' in rule: + module.fail_json(msg="Specify group_id OR cidr_ipv6, not both") + elif 'group_name' in rule and 'cidr_ipv6' in rule: + module.fail_json(msg="Specify group_name OR cidr_ipv6, not both") + elif 'group_id' in rule and 'group_name' in rule: + module.fail_json(msg="Specify group_id OR group_name, not both") + elif 'cidr_ip' in rule and 'cidr_ipv6' in rule: + module.fail_json(msg="Specify cidr_ip OR cidr_ipv6, not both") + elif rule.get('group_id') and re.match(FOREIGN_SECURITY_GROUP_REGEX, rule['group_id']): + # this is a foreign Security Group. Since you can't fetch it you must create an instance of it + owner_id, group_id, group_name = re.match(FOREIGN_SECURITY_GROUP_REGEX, rule['group_id']).groups() + group_instance = dict(GroupId=group_id, GroupName=group_name) + groups[group_id] = group_instance + groups[group_name] = group_instance + elif 'group_id' in rule: + group_id = rule['group_id'] + elif 'group_name' in rule: + group_name = rule['group_name'] + if group_name == name: + group_id = group['GroupId'] + groups[group_id] = group + groups[group_name] = group + elif group_name in groups and group.get('VpcId') and groups[group_name].get('VpcId'): + # both are VPC groups, this is ok + group_id = groups[group_name]['GroupId'] + elif group_name in groups and not (group.get('VpcId') or groups[group_name].get('VpcId')): + # both are EC2 classic, this is ok + group_id = groups[group_name]['GroupId'] + else: + # if we got here, either the target group does not exist, or there + # is a mix of EC2 classic + VPC groups. Mixing of EC2 classic + VPC + # is bad, so we have to create a new SG because no compatible group + # exists + if not rule.get('group_desc', '').strip(): + module.fail_json(msg="group %s will be automatically created by rule %s and " + "no description was provided" % (group_name, rule)) + if not module.check_mode: + params = dict(GroupName=group_name, Description=rule['group_desc']) + if vpc_id: + params['VpcId'] = vpc_id + auto_group = client.create_security_group(**params) + group_id = auto_group['GroupId'] + groups[group_id] = auto_group + groups[group_name] = auto_group + target_group_created = True + elif 'cidr_ip' in rule: + ip = rule['cidr_ip'] + elif 'cidr_ipv6' in rule: + ipv6 = rule['cidr_ipv6'] + + return group_id, ip, ipv6, target_group_created + + +def ports_expand(ports): + # takes a list of ports and returns a list of (port_from, port_to) + ports_expanded = [] + for port in ports: + if not isinstance(port, str): + ports_expanded.append((port,) * 2) + elif '-' in port: + ports_expanded.append(tuple(p.strip() for p in port.split('-', 1))) + else: + ports_expanded.append((port.strip(),) * 2) + + return ports_expanded + + +def rule_expand_ports(rule): + # takes a rule dict and returns a list of expanded rule dicts + if 'ports' not in rule: + return [rule] + + ports = rule['ports'] if isinstance(rule['ports'], list) else [rule['ports']] + + rule_expanded = [] + for from_to in ports_expand(ports): + temp_rule = rule.copy() + del temp_rule['ports'] + temp_rule['from_port'], temp_rule['to_port'] = from_to + rule_expanded.append(temp_rule) + + return rule_expanded + + +def rules_expand_ports(rules): + # takes a list of rules and expands it based on 'ports' + if not rules: + return rules + + return [rule for rule_complex in rules + for rule in rule_expand_ports(rule_complex)] + + +def rule_expand_source(rule, source_type): + # takes a rule dict and returns a list of expanded rule dicts for specified source_type + sources = rule[source_type] if isinstance(rule[source_type], list) else [rule[source_type]] + source_types_all = ('cidr_ip', 'cidr_ipv6', 'group_id', 'group_name') + + rule_expanded = [] + for source in sources: + temp_rule = rule.copy() + for s in source_types_all: + temp_rule.pop(s, None) + temp_rule[source_type] = source + rule_expanded.append(temp_rule) + + return rule_expanded + + +def rule_expand_sources(rule): + # takes a rule dict and returns a list of expanded rule discts + source_types = (stype for stype in ('cidr_ip', 'cidr_ipv6', 'group_id', 'group_name') if stype in rule) + + return [r for stype in source_types + for r in rule_expand_source(rule, stype)] + + +def rules_expand_sources(rules): + # takes a list of rules and expands it based on 'cidr_ip', 'group_id', 'group_name' + if not rules: + return rules + + return [rule for rule_complex in rules + for rule in rule_expand_sources(rule_complex)] + + +def authorize_ip(type, changed, client, group, groupRules, + ip, ip_permission, module, rule, ethertype): + # If rule already exists, don't later delete it + for thisip in ip: + rule_id = make_rule_key(type, rule, group['GroupId'], thisip) + if rule_id in groupRules: + del groupRules[rule_id] + else: + if not module.check_mode: + ip_permission = serialize_ip_grant(rule, thisip, ethertype) + if ip_permission: + try: + if type == "in": + client.authorize_security_group_ingress(GroupId=group['GroupId'], + IpPermissions=[ip_permission]) + elif type == "out": + client.authorize_security_group_egress(GroupId=group['GroupId'], + IpPermissions=[ip_permission]) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Unable to authorize %s for ip %s security group '%s' - %s" % + (type, thisip, group['GroupName'], e), + exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + return changed, ip_permission + + +def serialize_group_grant(group_id, rule): + permission = {'IpProtocol': rule['proto'], + 'FromPort': rule['from_port'], + 'ToPort': rule['to_port'], + 'UserIdGroupPairs': [{'GroupId': group_id}]} + + return fix_port_and_protocol(permission) + + +def serialize_revoke(grant, rule): + permission = dict() + fromPort = rule['FromPort'] if 'FromPort' in rule else None + toPort = rule['ToPort'] if 'ToPort' in rule else None + if 'GroupId' in grant: + permission = {'IpProtocol': rule['IpProtocol'], + 'FromPort': fromPort, + 'ToPort': toPort, + 'UserIdGroupPairs': [{'GroupId': grant['GroupId']}] + } + elif 'CidrIp' in grant: + permission = {'IpProtocol': rule['IpProtocol'], + 'FromPort': fromPort, + 'ToPort': toPort, + 'IpRanges': [grant] + } + elif 'CidrIpv6' in grant: + permission = {'IpProtocol': rule['IpProtocol'], + 'FromPort': fromPort, + 'ToPort': toPort, + 'Ipv6Ranges': [grant] + } + return fix_port_and_protocol(permission) + + +def serialize_ip_grant(rule, thisip, ethertype): + permission = {'IpProtocol': rule['proto'], + 'FromPort': rule['from_port'], + 'ToPort': rule['to_port']} + if ethertype == "ipv4": + permission['IpRanges'] = [{'CidrIp': thisip}] + elif ethertype == "ipv6": + permission['Ipv6Ranges'] = [{'CidrIpv6': thisip}] + + return fix_port_and_protocol(permission) + + +def fix_port_and_protocol(permission): + for key in ['FromPort', 'ToPort']: + if key in permission: + if permission[key] is None: + del permission[key] + else: + permission[key] = int(permission[key]) + + permission['IpProtocol'] = str(permission['IpProtocol']) + + return permission + + +def main(): + argument_spec = ec2_argument_spec() + argument_spec.update(dict( + name=dict(), + group_id=dict(), + description=dict(), + vpc_id=dict(), + rules=dict(type='list'), + rules_egress=dict(type='list'), + state=dict(default='present', type='str', choices=['present', 'absent']), + purge_rules=dict(default=True, required=False, type='bool'), + purge_rules_egress=dict(default=True, required=False, type='bool'), + tags=dict(required=False, type='dict', aliases=['resource_tags']), + purge_tags=dict(default=True, required=False, type='bool') + ) + ) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_one_of=[['name', 'group_id']], + required_if=[['state', 'present', ['name']]], + ) + + if not HAS_BOTO3: + module.fail_json(msg='boto3 required for this module') + + name = module.params['name'] + group_id = module.params['group_id'] + description = module.params['description'] + vpc_id = module.params['vpc_id'] + rules = deduplicate_rules_args(rules_expand_sources(rules_expand_ports(module.params['rules']))) + rules_egress = deduplicate_rules_args(rules_expand_sources(rules_expand_ports(module.params['rules_egress']))) + state = module.params.get('state') + purge_rules = module.params['purge_rules'] + purge_rules_egress = module.params['purge_rules_egress'] + tags = module.params['tags'] + purge_tags = module.params['purge_tags'] + + if state == 'present' and not description: + module.fail_json(msg='Must provide description when state is present.') + + changed = False + region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True) + if not region: + module.fail_json(msg="The AWS region must be specified as an " + "environment variable or in the AWS credentials " + "profile.") + client = boto3_conn(module, conn_type='client', resource='ec2', endpoint=ec2_url, region=region, **aws_connect_params) + group = None + groups = dict() + security_groups = [] + # do get all security groups + # find if the group is present + try: + response = get_security_groups_with_backoff(client) + security_groups = response.get('SecurityGroups', []) + except botocore.exceptions.NoCredentialsError as e: + module.fail_json(msg="Error in describe_security_groups: %s" % "Unable to locate credentials", exception=traceback.format_exc()) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Error in describe_security_groups: %s" % e, exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + + for sg in security_groups: + groups[sg['GroupId']] = sg + groupName = sg['GroupName'] + if groupName in groups: + # Prioritise groups from the current VPC + # even if current VPC is EC2-Classic + if groups[groupName].get('VpcId') == vpc_id: + # Group saved already matches current VPC, change nothing + pass + elif vpc_id is None and groups[groupName].get('VpcId') is None: + # We're in EC2 classic, and the group already saved is as well + # No VPC groups can be used alongside EC2 classic groups + pass + else: + # the current SG stored has no direct match, so we can replace it + groups[groupName] = sg + else: + groups[groupName] = sg + + if group_id and sg['GroupId'] == group_id: + group = sg + elif groupName == name and (vpc_id is None or sg.get('VpcId') == vpc_id): + group = sg + + # Ensure requested group is absent + if state == 'absent': + if group: + # found a match, delete it + try: + if not module.check_mode: + client.delete_security_group(GroupId=group['GroupId']) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Unable to delete security group '%s' - %s" % (group, e), + exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + else: + group = None + changed = True + else: + # no match found, no changes required + pass + + # Ensure requested group is present + elif state == 'present': + if group: + # existing group + if group['Description'] != description: + module.warn("Group description does not match existing group. Descriptions cannot be changed without deleting " + "and re-creating the security group. Try using state=absent to delete, then rerunning this task.") + + # if the group doesn't exist, create it now + else: + # no match found, create it + if not module.check_mode: + params = dict(GroupName=name, Description=description) + if vpc_id: + params['VpcId'] = vpc_id + group = client.create_security_group(**params) + # When a group is created, an egress_rule ALLOW ALL + # to 0.0.0.0/0 is added automatically but it's not + # reflected in the object returned by the AWS API + # call. We re-read the group for getting an updated object + # amazon sometimes takes a couple seconds to update the security group so wait till it exists + while True: + group = get_security_groups_with_backoff(client, GroupIds=[group['GroupId']])['SecurityGroups'][0] + if group.get('VpcId') and not group.get('IpPermissionsEgress'): + pass + else: + break + + changed = True + + if tags is not None: + current_tags = boto3_tag_list_to_ansible_dict(group.get('Tags', [])) + tags_need_modify, tags_to_delete = compare_aws_tags(current_tags, tags, purge_tags) + if tags_to_delete: + try: + client.delete_tags(Resources=[group['GroupId']], Tags=[{'Key': tag} for tag in tags_to_delete]) + except botocore.exceptions.ClientError as e: + module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + + # Add/update tags + if tags_need_modify: + try: + client.create_tags(Resources=[group['GroupId']], Tags=ansible_dict_to_boto3_tag_list(tags_need_modify)) + except botocore.exceptions.ClientError as e: + module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + + else: + module.fail_json(msg="Unsupported state requested: %s" % state) + + # create a lookup for all existing rules on the group + ip_permission = [] + if group: + # Manage ingress rules + groupRules = {} + add_rules_to_lookup(group['IpPermissions'], group['GroupId'], 'in', groupRules) + # Now, go through all provided rules and ensure they are there. + if rules is not None: + for rule in rules: + validate_rule(module, rule) + group_id, ip, ipv6, target_group_created = get_target_from_rule(module, client, rule, name, + group, groups, vpc_id) + if target_group_created: + changed = True + + if rule['proto'] in ('all', '-1', -1): + rule['proto'] = -1 + rule['from_port'] = None + rule['to_port'] = None + + if group_id: + rule_id = make_rule_key('in', rule, group['GroupId'], group_id) + if rule_id in groupRules: + del groupRules[rule_id] + else: + if not module.check_mode: + ip_permission = serialize_group_grant(group_id, rule) + if ip_permission: + ips = ip_permission + if vpc_id: + [useridpair.update({'VpcId': vpc_id}) for useridpair in + ip_permission.get('UserIdGroupPairs', [])] + try: + client.authorize_security_group_ingress(GroupId=group['GroupId'], IpPermissions=[ips]) + except botocore.exceptions.ClientError as e: + module.fail_json( + msg="Unable to authorize ingress for group %s security group '%s' - %s" % + (group_id, group['GroupName'], e), + exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + elif ip: + # Convert ip to list we can iterate over + if ip and not isinstance(ip, list): + ip = [ip] + + changed, ip_permission = authorize_ip("in", changed, client, group, groupRules, ip, ip_permission, + module, rule, "ipv4") + elif ipv6: + # Convert ip to list we can iterate over + if not isinstance(ipv6, list): + ipv6 = [ipv6] + # If rule already exists, don't later delete it + changed, ip_permission = authorize_ip("in", changed, client, group, groupRules, ipv6, ip_permission, + module, rule, "ipv6") + # Finally, remove anything left in the groupRules -- these will be defunct rules + if purge_rules: + for (rule, grant) in groupRules.values(): + ip_permission = serialize_revoke(grant, rule) + if not module.check_mode: + try: + client.revoke_security_group_ingress(GroupId=group['GroupId'], IpPermissions=[ip_permission]) + except botocore.exceptions.ClientError as e: + module.fail_json( + msg="Unable to revoke ingress for security group '%s' - %s" % + (group['GroupName'], e), + exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + + # Manage egress rules + groupRules = {} + add_rules_to_lookup(group['IpPermissionsEgress'], group['GroupId'], 'out', groupRules) + # Now, go through all provided rules and ensure they are there. + if rules_egress is not None: + for rule in rules_egress: + validate_rule(module, rule) + group_id, ip, ipv6, target_group_created = get_target_from_rule(module, client, rule, name, + group, groups, vpc_id) + if target_group_created: + changed = True + + if rule['proto'] in ('all', '-1', -1): + rule['proto'] = -1 + rule['from_port'] = None + rule['to_port'] = None + + if group_id: + rule_id = make_rule_key('out', rule, group['GroupId'], group_id) + if rule_id in groupRules: + del groupRules[rule_id] + else: + if not module.check_mode: + ip_permission = serialize_group_grant(group_id, rule) + if ip_permission: + ips = ip_permission + if vpc_id: + [useridpair.update({'VpcId': vpc_id}) for useridpair in + ip_permission.get('UserIdGroupPairs', [])] + try: + client.authorize_security_group_egress(GroupId=group['GroupId'], IpPermissions=[ips]) + except botocore.exceptions.ClientError as e: + module.fail_json( + msg="Unable to authorize egress for group %s security group '%s' - %s" % + (group_id, group['GroupName'], e), + exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + elif ip: + # Convert ip to list we can iterate over + if not isinstance(ip, list): + ip = [ip] + changed, ip_permission = authorize_ip("out", changed, client, group, groupRules, ip, + ip_permission, module, rule, "ipv4") + elif ipv6: + # Convert ip to list we can iterate over + if not isinstance(ipv6, list): + ipv6 = [ipv6] + # If rule already exists, don't later delete it + changed, ip_permission = authorize_ip("out", changed, client, group, groupRules, ipv6, + ip_permission, module, rule, "ipv6") + elif vpc_id is not None: + # when no egress rules are specified and we're in a VPC, + # we add in a default allow all out rule, which was the + # default behavior before egress rules were added + default_egress_rule = 'out--1-None-None-' + group['GroupId'] + '-0.0.0.0/0' + if default_egress_rule not in groupRules: + if not module.check_mode: + ip_permission = [{'IpProtocol': '-1', + 'IpRanges': [{'CidrIp': '0.0.0.0/0'}] + } + ] + try: + client.authorize_security_group_egress(GroupId=group['GroupId'], IpPermissions=ip_permission) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Unable to authorize egress for ip %s security group '%s' - %s" % + ('0.0.0.0/0', + group['GroupName'], + e), + exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + else: + # make sure the default egress rule is not removed + del groupRules[default_egress_rule] + + # Finally, remove anything left in the groupRules -- these will be defunct rules + if purge_rules_egress and vpc_id is not None: + for (rule, grant) in groupRules.values(): + # we shouldn't be revoking 0.0.0.0 egress + if grant != '0.0.0.0/0': + ip_permission = serialize_revoke(grant, rule) + if not module.check_mode: + try: + client.revoke_security_group_egress(GroupId=group['GroupId'], IpPermissions=[ip_permission]) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Unable to revoke egress for ip %s security group '%s' - %s" % + (grant, group['GroupName'], e), + exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) + changed = True + + if group: + security_group = get_security_groups_with_backoff(client, GroupIds=[group['GroupId']])['SecurityGroups'][0] + security_group = camel_dict_to_snake_dict(security_group) + security_group['tags'] = boto3_tag_list_to_ansible_dict(security_group.get('tags', []), + tag_name_key_name='key', tag_value_key_name='value') + module.exit_json(changed=changed, **security_group) + else: + module.exit_json(changed=changed, group_id=None) + + +if __name__ == '__main__': + main() diff --git a/roles/openshift_aws/defaults/main.yml b/roles/openshift_aws/defaults/main.yml index 42ef22846..74e5d1dde 100644 --- a/roles/openshift_aws/defaults/main.yml +++ b/roles/openshift_aws/defaults/main.yml @@ -6,9 +6,7 @@ openshift_aws_create_security_groups: True openshift_aws_create_launch_config: True openshift_aws_create_scale_group: True -openshift_aws_current_version: '' -openshift_aws_new_version: '' - +openshift_aws_node_group_upgrade: False openshift_aws_wait_for_ssh: True openshift_aws_clusterid: default @@ -19,7 +17,6 @@ openshift_aws_build_ami_group: "{{ openshift_aws_clusterid }}" openshift_aws_iam_cert_name: "{{ openshift_aws_clusterid }}-master-external" openshift_aws_iam_cert_path: '' openshift_aws_iam_cert_key_path: '' -openshift_aws_scale_group_basename: "{{ openshift_aws_clusterid }} openshift" openshift_aws_iam_role_name: openshift_node_describe_instances openshift_aws_iam_role_policy_json: "{{ lookup('file', 'describeinstances.json') }}" @@ -34,14 +31,12 @@ openshift_aws_ami_name: openshift-gi openshift_aws_base_ami_name: ami_base openshift_aws_launch_config_bootstrap_token: '' -openshift_aws_launch_config_basename: "{{ openshift_aws_clusterid }}" openshift_aws_users: [] openshift_aws_ami_tags: bootstrap: "true" openshift-created: "true" - clusterid: "{{ openshift_aws_clusterid }}" parent: "{{ openshift_aws_base_ami | default('unknown') }}" openshift_aws_s3_mode: create @@ -124,6 +119,20 @@ openshift_aws_ami_map: infra: "{{ openshift_aws_ami }}" compute: "{{ openshift_aws_ami }}" +openshift_aws_master_group: +- name: "{{ openshift_aws_clusterid }} master group" + group: master + +openshift_aws_node_groups: +- name: "{{ openshift_aws_clusterid }} compute group" + group: compute +- name: "{{ openshift_aws_clusterid }} infra group" + group: infra + +openshift_aws_created_asgs: [] +openshift_aws_current_asgs: [] + +# these will be used during upgrade openshift_aws_master_group_config: # The 'master' key is always required here. master: @@ -139,7 +148,6 @@ openshift_aws_master_group_config: host-type: master sub-host-type: default runtime: docker - version: "{{ openshift_aws_new_version }}" wait_for_instances: True termination_policy: "{{ openshift_aws_node_group_termination_policy }}" replace_all_instances: "{{ openshift_aws_node_group_replace_all_instances }}" @@ -163,7 +171,6 @@ openshift_aws_node_group_config: host-type: node sub-host-type: compute runtime: docker - version: "{{ openshift_aws_new_version }}" termination_policy: "{{ openshift_aws_node_group_termination_policy }}" replace_all_instances: "{{ openshift_aws_node_group_replace_all_instances }}" iam_role: "{{ openshift_aws_iam_role_name }}" @@ -183,7 +190,6 @@ openshift_aws_node_group_config: host-type: node sub-host-type: infra runtime: docker - version: "{{ openshift_aws_new_version }}" termination_policy: "{{ openshift_aws_node_group_termination_policy }}" replace_all_instances: "{{ openshift_aws_node_group_replace_all_instances }}" iam_role: "{{ openshift_aws_iam_role_name }}" @@ -283,21 +289,4 @@ openshift_aws_node_run_bootstrap_startup: True openshift_aws_node_user_data: '' openshift_aws_node_config_namespace: openshift-node -openshift_aws_node_groups: nodes - openshift_aws_masters_groups: masters,etcd,nodes - -# If creating extra node groups, you'll need to define all of the following - -# The format is the same as openshift_aws_node_group_config, but the top-level -# key names should be different (ie, not == master or infra). -# openshift_aws_node_group_config_extra: {} - -# This variable should look like openshift_aws_launch_config_security_groups -# and contain a one-to-one mapping of top level keys that are defined in -# openshift_aws_node_group_config_extra. -# openshift_aws_launch_config_security_groups_extra: {} - -# openshift_aws_node_security_groups_extra: {} - -# openshift_aws_ami_map_extra: {} diff --git a/roles/openshift_aws/filter_plugins/openshift_aws_filters.py b/roles/openshift_aws/filter_plugins/openshift_aws_filters.py index e707abd3f..dfcb11da3 100644 --- a/roles/openshift_aws/filter_plugins/openshift_aws_filters.py +++ b/roles/openshift_aws/filter_plugins/openshift_aws_filters.py @@ -4,11 +4,43 @@ Custom filters for use in openshift_aws ''' +from ansible import errors + class FilterModule(object): ''' Custom ansible filters for use by openshift_aws role''' @staticmethod + def scale_groups_serial(scale_group_info, upgrade=False): + ''' This function will determine what the deployment serial should be and return it + + Search through the tags and find the deployment_serial tag. Once found, + determine if an increment is needed during an upgrade. + if upgrade is true then increment the serial and return it + else return the serial + ''' + if scale_group_info == []: + return 1 + + scale_group_info = scale_group_info[0] + + if not isinstance(scale_group_info, dict): + raise errors.AnsibleFilterError("|filter plugin failed: Expected scale_group_info to be a dict") + + serial = None + + for tag in scale_group_info['tags']: + if tag['key'] == 'deployment_serial': + serial = int(tag['value']) + if upgrade: + serial += 1 + break + else: + raise errors.AnsibleFilterError("|filter plugin failed: deployment_serial tag was not found") + + return serial + + @staticmethod def scale_groups_match_capacity(scale_group_info): ''' This function will verify that the scale group instance count matches the scale group desired capacity @@ -38,4 +70,5 @@ class FilterModule(object): def filters(self): ''' returns a mapping of filters to methods ''' return {'build_instance_tags': self.build_instance_tags, - 'scale_groups_match_capacity': self.scale_groups_match_capacity} + 'scale_groups_match_capacity': self.scale_groups_match_capacity, + 'scale_groups_serial': self.scale_groups_serial} diff --git a/roles/openshift_aws/tasks/accept_nodes.yml b/roles/openshift_aws/tasks/accept_nodes.yml index ae320962f..c2a2cea30 100644 --- a/roles/openshift_aws/tasks/accept_nodes.yml +++ b/roles/openshift_aws/tasks/accept_nodes.yml @@ -1,6 +1,6 @@ --- - name: fetch masters - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region | default('us-east-1') }}" filters: "{{ {'tag:kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid, @@ -11,7 +11,7 @@ until: "'instances' in mastersout and mastersout.instances|length > 0" - name: fetch new node instances - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: "{{ {'tag:kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid, @@ -22,9 +22,14 @@ delay: 3 until: "'instances' in instancesout and instancesout.instances|length > 0" -- debug: +- name: Dump the private dns names + debug: msg: "{{ instancesout.instances|map(attribute='private_dns_name') | list }}" +- name: Dump the master public ip address + debug: + msg: "{{ mastersout.instances[0].public_ip_address }}" + - name: approve nodes oc_adm_csr: #approve_all: True diff --git a/roles/openshift_aws/tasks/build_node_group.yml b/roles/openshift_aws/tasks/build_node_group.yml index 2c1e88cfb..7fb617dd5 100644 --- a/roles/openshift_aws/tasks/build_node_group.yml +++ b/roles/openshift_aws/tasks/build_node_group.yml @@ -1,6 +1,4 @@ --- -# This task file expects l_nodes_to_build to be passed in. - # When openshift_aws_use_custom_ami is '' then # we retrieve the latest build AMI. # Then set openshift_aws_ami to the ami. @@ -26,6 +24,35 @@ # Need to set epoch time in one place to use for launch_config and scale_group - set_fact: l_epoch_time: "{{ ansible_date_time.epoch }}" +# +# query asg's and determine if we need to create the others. +# if we find more than 1 for each type, then exit +- name: query all asg's for this cluster + ec2_asg_facts: + region: "{{ openshift_aws_region }}" + tags: "{{ {'kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid} | combine(l_node_group_config[openshift_aws_node_group.group].tags) }}" + register: asgs + +- fail: + msg: "Found more than 1 auto scaling group that matches the query for group: {{ openshift_aws_node_group }}" + when: + - asgs.results|length > 1 + +- debug: + msg: "{{ asgs }}" + +- name: set the value for the deployment_serial and the current asgs + set_fact: + l_deployment_serial: "{{ openshift_aws_node_group_deployment_serial if openshift_aws_node_group_deployment_serial is defined else asgs.results | scale_groups_serial(openshift_aws_node_group_upgrade) }}" + openshift_aws_current_asgs: "{{ asgs.results | map(attribute='auto_scaling_group_name') | list | union(openshift_aws_current_asgs) }}" + +- name: dump deployment serial + debug: + msg: "Deployment serial: {{ l_deployment_serial }}" + +- name: dump current_asgs + debug: + msg: "openshift_aws_current_asgs: {{ openshift_aws_current_asgs }}" - when: openshift_aws_create_iam_role include_tasks: iam_role.yml diff --git a/roles/openshift_aws/tasks/iam_role.yml b/roles/openshift_aws/tasks/iam_role.yml index d9910d938..cf3bb28fb 100644 --- a/roles/openshift_aws/tasks/iam_role.yml +++ b/roles/openshift_aws/tasks/iam_role.yml @@ -13,11 +13,10 @@ ##### - name: Create an iam role iam_role: - name: "{{ item.value.iam_role }}" + name: "{{ l_node_group_config[openshift_aws_node_group.group].iam_role }}" assume_role_policy_document: "{{ lookup('file','trustpolicy.json') }}" state: "{{ openshift_aws_iam_role_state | default('present') }}" - when: item.value.iam_role is defined - with_dict: "{{ l_nodes_to_build }}" + when: l_node_group_config[openshift_aws_node_group.group].iam_role is defined ##### # The second part of this task file is linking the role to a policy @@ -28,9 +27,8 @@ - name: create an iam policy iam_policy: iam_type: role - iam_name: "{{ item.value.iam_role }}" - policy_json: "{{ item.value.policy_json }}" - policy_name: "{{ item.value.policy_name }}" + iam_name: "{{ l_node_group_config[openshift_aws_node_group.group].iam_role }}" + policy_json: "{{ l_node_group_config[openshift_aws_node_group.group].policy_json }}" + policy_name: "{{ l_node_group_config[openshift_aws_node_group.group].policy_name }}" state: "{{ openshift_aws_iam_role_state | default('present') }}" - when: item.value.iam_role is defined - with_dict: "{{ l_nodes_to_build }}" + when: "'iam_role' in l_node_group_config[openshift_aws_node_group.group]" diff --git a/roles/openshift_aws/tasks/launch_config.yml b/roles/openshift_aws/tasks/launch_config.yml index fed80b7eb..6f78ee00a 100644 --- a/roles/openshift_aws/tasks/launch_config.yml +++ b/roles/openshift_aws/tasks/launch_config.yml @@ -1,15 +1,26 @@ --- -- fail: - msg: "Ensure that an AMI value is defined for openshift_aws_ami or openshift_aws_launch_config_custom_image." - when: - - openshift_aws_ami is undefined +- name: fetch the security groups for launch config + ec2_group_facts: + filters: + group-name: "{{ openshift_aws_launch_config_security_groups[openshift_aws_node_group.group] }}" + vpc-id: "{{ vpcout.vpcs[0].id }}" + region: "{{ openshift_aws_region }}" + register: ec2sgs -- fail: - msg: "Ensure that openshift_deployment_type is defined." - when: - - openshift_deployment_type is undefined - -- include_tasks: launch_config_create.yml - with_dict: "{{ l_nodes_to_build }}" - loop_control: - loop_var: launch_config_item +# Create the scale group config +- name: Create the node scale group launch config + ec2_lc: + name: "{{ openshift_aws_node_group.name }}-{{ openshift_aws_ami_map[openshift_aws_node_group.group] | default(openshift_aws_ami) }}-{{ l_epoch_time }}" + region: "{{ openshift_aws_region }}" + image_id: "{{ openshift_aws_ami_map[openshift_aws_node_group.group] | default(openshift_aws_ami) }}" + instance_type: "{{ l_node_group_config[openshift_aws_node_group.group].instance_type }}" + security_groups: "{{ openshift_aws_launch_config_security_group_id | default(ec2sgs.security_groups | map(attribute='group_id')| list) }}" + instance_profile_name: "{{ l_node_group_config[openshift_aws_node_group.group].iam_role if l_node_group_config[openshift_aws_node_group.group].iam_role is defined and + l_node_group_config[openshift_aws_node_group.group].iam_role != '' and + openshift_aws_create_iam_role + else omit }}" + user_data: "{{ lookup('template', 'user_data.j2') }}" + key_name: "{{ openshift_aws_ssh_key_name }}" + ebs_optimized: False + volumes: "{{ l_node_group_config[openshift_aws_node_group.group].volumes }}" + assign_public_ip: True diff --git a/roles/openshift_aws/tasks/launch_config_create.yml b/roles/openshift_aws/tasks/launch_config_create.yml deleted file mode 100644 index f7f0f0953..000000000 --- a/roles/openshift_aws/tasks/launch_config_create.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -- name: fetch the security groups for launch config - ec2_group_facts: - filters: - group-name: "{{ l_launch_config_security_groups[launch_config_item.key] }}" - vpc-id: "{{ vpcout.vpcs[0].id }}" - region: "{{ openshift_aws_region }}" - register: ec2sgs - -# Create the scale group config -- name: Create the node scale group launch config - ec2_lc: - name: "{{ openshift_aws_launch_config_basename }}-{{ launch_config_item.key }}{{'-' ~ openshift_aws_new_version if openshift_aws_new_version != '' else '' }}" - region: "{{ openshift_aws_region }}" - image_id: "{{ l_aws_ami_map[launch_config_item.key] | default(openshift_aws_ami) }}" - instance_type: "{{ launch_config_item.value.instance_type }}" - security_groups: "{{ openshift_aws_launch_config_security_group_id | default(ec2sgs.security_groups | map(attribute='group_id')| list) }}" - instance_profile_name: "{{ launch_config_item.value.iam_role if launch_config_item.value.iam_role is defined and - launch_config_item.value.iam_role != '' and - openshift_aws_create_iam_role - else omit }}" - user_data: "{{ lookup('template', 'user_data.j2') }}" - key_name: "{{ openshift_aws_ssh_key_name }}" - ebs_optimized: False - volumes: "{{ launch_config_item.value.volumes }}" - assign_public_ip: True diff --git a/roles/openshift_aws/tasks/provision.yml b/roles/openshift_aws/tasks/provision.yml index 06f649343..786a2e4cf 100644 --- a/roles/openshift_aws/tasks/provision.yml +++ b/roles/openshift_aws/tasks/provision.yml @@ -20,13 +20,14 @@ - name: include scale group creation for master include_tasks: build_node_group.yml + with_items: "{{ openshift_aws_master_group }}" vars: - l_nodes_to_build: "{{ openshift_aws_master_group_config }}" - l_launch_config_security_groups: "{{ openshift_aws_launch_config_security_groups }}" - l_aws_ami_map: "{{ openshift_aws_ami_map }}" + l_node_group_config: "{{ openshift_aws_master_group_config }}" + loop_control: + loop_var: openshift_aws_node_group - name: fetch newly created instances - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: "tag:clusterid": "{{ openshift_aws_clusterid }}" diff --git a/roles/openshift_aws/tasks/provision_instance.yml b/roles/openshift_aws/tasks/provision_instance.yml index 8cc75cd0c..696b323c0 100644 --- a/roles/openshift_aws/tasks/provision_instance.yml +++ b/roles/openshift_aws/tasks/provision_instance.yml @@ -27,7 +27,7 @@ Name: "{{ openshift_aws_base_ami_name }}" - name: fetch newly created instances - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: "tag:Name": "{{ openshift_aws_base_ami_name }}" diff --git a/roles/openshift_aws/tasks/provision_nodes.yml b/roles/openshift_aws/tasks/provision_nodes.yml index 041ed0791..d82f18574 100644 --- a/roles/openshift_aws/tasks/provision_nodes.yml +++ b/roles/openshift_aws/tasks/provision_nodes.yml @@ -3,7 +3,7 @@ # bootstrap should be created on first master # need to fetch it and shove it into cloud data - name: fetch master instances - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: "tag:clusterid": "{{ openshift_aws_clusterid }}" @@ -31,20 +31,15 @@ - name: include build compute and infra node groups include_tasks: build_node_group.yml + with_items: "{{ openshift_aws_node_groups }}" vars: - l_nodes_to_build: "{{ openshift_aws_node_group_config }}" - l_launch_config_security_groups: "{{ openshift_aws_launch_config_security_groups }}" - l_aws_ami_map: "{{ openshift_aws_ami_map }}" - -- name: include build node group for extra nodes - include_tasks: build_node_group.yml - when: openshift_aws_node_group_config_extra is defined - vars: - l_nodes_to_build: "{{ openshift_aws_node_group_config_extra | default({}) }}" - l_launch_config_security_groups: "{{ openshift_aws_launch_config_security_groups_extra }}" - l_aws_ami_map: "{{ openshift_aws_ami_map_extra }}" + l_node_group_config: "{{ openshift_aws_node_group_config }}" + loop_control: + loop_var: openshift_aws_node_group # instances aren't scaling fast enough here, we need to wait for them - when: openshift_aws_wait_for_ssh | bool name: wait for our new nodes to come up include_tasks: wait_for_groups.yml + vars: + created_asgs: "{{ openshift_aws_created_asgs }}" diff --git a/roles/openshift_aws/tasks/remove_scale_group.yml b/roles/openshift_aws/tasks/remove_scale_group.yml index 55d1af2b5..a01cde294 100644 --- a/roles/openshift_aws/tasks/remove_scale_group.yml +++ b/roles/openshift_aws/tasks/remove_scale_group.yml @@ -1,10 +1,13 @@ --- +# FIGURE OUT HOW TO REMOVE SCALE GROUPS +# use openshift_aws_current_asgs?? - name: fetch the scale groups ec2_asg_facts: region: "{{ openshift_aws_region }}" + name: "^{{ item }}$" tags: - "{{ {'kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid, - 'version': openshift_aws_current_version} }}" + "{{ {'kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid} }}" + with_items: "{{ openshift_aws_current_asgs if openshift_aws_current_asgs != [] else openshift_aws_asgs_to_remove }}" register: qasg - name: remove non-master scale groups @@ -14,7 +17,7 @@ name: "{{ item.auto_scaling_group_name }}" when: "'master' not in item.auto_scaling_group_name" register: asg_results - with_items: "{{ qasg.results }}" + with_items: "{{ qasg | json_query('results[*]') | sum(attribute='results', start=[]) }}" async: 600 poll: 0 diff --git a/roles/openshift_aws/tasks/s3.yml b/roles/openshift_aws/tasks/s3.yml index 9cf37c840..ba70bcff6 100644 --- a/roles/openshift_aws/tasks/s3.yml +++ b/roles/openshift_aws/tasks/s3.yml @@ -1,6 +1,6 @@ --- - name: Create an s3 bucket - s3: + aws_s3: bucket: "{{ openshift_aws_s3_bucket_name }}" mode: "{{ openshift_aws_s3_mode }}" region: "{{ openshift_aws_region }}" diff --git a/roles/openshift_aws/tasks/scale_group.yml b/roles/openshift_aws/tasks/scale_group.yml index 30df7545d..3632f7ce9 100644 --- a/roles/openshift_aws/tasks/scale_group.yml +++ b/roles/openshift_aws/tasks/scale_group.yml @@ -1,20 +1,30 @@ --- +- name: set node group name + set_fact: + l_node_group_name: "{{ openshift_aws_node_group.name }} {{ l_deployment_serial }}" + - name: Create the scale group ec2_asg: - name: "{{ openshift_aws_scale_group_basename }} {{ item.key }}" - launch_config_name: "{{ openshift_aws_launch_config_basename }}-{{ item.key }}{{ '-' ~ openshift_aws_new_version if openshift_aws_new_version != '' else '' }}" - health_check_period: "{{ item.value.health_check.period }}" - health_check_type: "{{ item.value.health_check.type }}" - min_size: "{{ item.value.min_size }}" - max_size: "{{ item.value.max_size }}" - desired_capacity: "{{ item.value.desired_size }}" + name: "{{ l_node_group_name }}" + launch_config_name: "{{ openshift_aws_node_group.name }}-{{ openshift_aws_ami_map[openshift_aws_node_group.group] | default(openshift_aws_ami) }}-{{ l_epoch_time }}" + health_check_period: "{{ l_node_group_config[openshift_aws_node_group.group].health_check.period }}" + health_check_type: "{{ l_node_group_config[openshift_aws_node_group.group].health_check.type }}" + min_size: "{{ l_node_group_config[openshift_aws_node_group.group].min_size }}" + max_size: "{{ l_node_group_config[openshift_aws_node_group.group].max_size }}" + desired_capacity: "{{ l_node_group_config[openshift_aws_node_group.group].desired_size }}" region: "{{ openshift_aws_region }}" - termination_policies: "{{ item.value.termination_policy if 'termination_policy' in item.value else omit }}" - load_balancers: "{{ item.value.elbs if 'elbs' in item.value else omit }}" - wait_for_instances: "{{ item.value.wait_for_instances | default(False)}}" + termination_policies: "{{ l_node_group_config[openshift_aws_node_group.group].termination_policy if 'termination_policy' in l_node_group_config[openshift_aws_node_group.group] else omit }}" + load_balancers: "{{ l_node_group_config[openshift_aws_node_group.group].elbs if 'elbs' in l_node_group_config[openshift_aws_node_group.group] else omit }}" + wait_for_instances: "{{ l_node_group_config[openshift_aws_node_group.group].wait_for_instances | default(False)}}" vpc_zone_identifier: "{{ subnetout.subnets[0].id }}" replace_instances: "{{ openshift_aws_node_group_replace_instances if openshift_aws_node_group_replace_instances != [] else omit }}" - replace_all_instances: "{{ omit if openshift_aws_node_group_replace_instances != [] else (item.value.replace_all_instances | default(omit)) }}" + replace_all_instances: "{{ omit if openshift_aws_node_group_replace_instances != [] + else (l_node_group_config[openshift_aws_node_group.group].replace_all_instances | default(omit)) }}" tags: - - "{{ openshift_aws_node_group_config_tags | combine(item.value.tags) }}" - with_dict: "{{ l_nodes_to_build }}" + - "{{ openshift_aws_node_group_config_tags + | combine(l_node_group_config[openshift_aws_node_group.group].tags) + | combine({'deployment_serial': l_deployment_serial, 'ami': openshift_aws_ami_map[openshift_aws_node_group.group] | default(openshift_aws_ami)}) }}" + +- name: append the asg name to the openshift_aws_created_asgs fact + set_fact: + openshift_aws_created_asgs: "{{ [l_node_group_name] | union(openshift_aws_created_asgs) | list }}" diff --git a/roles/openshift_aws/tasks/seal_ami.yml b/roles/openshift_aws/tasks/seal_ami.yml index 7a3d0fb68..74877d5c7 100644 --- a/roles/openshift_aws/tasks/seal_ami.yml +++ b/roles/openshift_aws/tasks/seal_ami.yml @@ -1,6 +1,6 @@ --- - name: fetch newly created instances - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: "tag:Name": "{{ openshift_aws_base_ami_name }}" @@ -12,7 +12,7 @@ - name: bundle ami ec2_ami: - instance_id: "{{ instancesout.instances.0.id }}" + instance_id: "{{ instancesout.instances.0.instance_id }}" region: "{{ openshift_aws_region }}" state: present description: "This was provisioned {{ ansible_date_time.iso8601 }}" @@ -46,4 +46,4 @@ ec2: state: absent region: "{{ openshift_aws_region }}" - instance_ids: "{{ instancesout.instances.0.id }}" + instance_ids: "{{ instancesout.instances.0.instance_id }}" diff --git a/roles/openshift_aws/tasks/security_group.yml b/roles/openshift_aws/tasks/security_group.yml index 43834079e..0568a0190 100644 --- a/roles/openshift_aws/tasks/security_group.yml +++ b/roles/openshift_aws/tasks/security_group.yml @@ -6,11 +6,27 @@ "tag:Name": "{{ openshift_aws_clusterid }}" register: vpcout -- include_tasks: security_group_create.yml - vars: - l_security_groups: "{{ openshift_aws_node_security_groups }}" +- name: create the node group sgs + oo_ec2_group: + name: "{{ item.value.name}}" + description: "{{ item.value.desc }}" + rules: "{{ item.value.rules if 'rules' in item.value else [] }}" + region: "{{ openshift_aws_region }}" + vpc_id: "{{ vpcout.vpcs[0].id }}" + with_dict: "{{ openshift_aws_node_security_groups }}" + +- name: create the k8s sgs for the node group + oo_ec2_group: + name: "{{ item.value.name }}_k8s" + description: "{{ item.value.desc }} for k8s" + region: "{{ openshift_aws_region }}" + vpc_id: "{{ vpcout.vpcs[0].id }}" + with_dict: "{{ openshift_aws_node_security_groups }}" + register: k8s_sg_create -- include_tasks: security_group_create.yml - when: openshift_aws_node_security_groups_extra is defined - vars: - l_security_groups: "{{ openshift_aws_node_security_groups_extra | default({}) }}" +- name: tag sg groups with proper tags + ec2_tag: + tags: "{{ openshift_aws_security_groups_tags }}" + resource: "{{ item.group_id }}" + region: "{{ openshift_aws_region }}" + with_items: "{{ k8s_sg_create.results }}" diff --git a/roles/openshift_aws/tasks/security_group_create.yml b/roles/openshift_aws/tasks/security_group_create.yml deleted file mode 100644 index ef6060555..000000000 --- a/roles/openshift_aws/tasks/security_group_create.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -- name: create the node group sgs - ec2_group: - name: "{{ item.value.name}}" - description: "{{ item.value.desc }}" - rules: "{{ item.value.rules if 'rules' in item.value else [] }}" - region: "{{ openshift_aws_region }}" - vpc_id: "{{ vpcout.vpcs[0].id }}" - with_dict: "{{ l_security_groups }}" - -- name: create the k8s sgs for the node group - ec2_group: - name: "{{ item.value.name }}_k8s" - description: "{{ item.value.desc }} for k8s" - region: "{{ openshift_aws_region }}" - vpc_id: "{{ vpcout.vpcs[0].id }}" - with_dict: "{{ l_security_groups }}" - register: k8s_sg_create - -- name: tag sg groups with proper tags - ec2_tag: - tags: "{{ openshift_aws_security_groups_tags }}" - resource: "{{ item.group_id }}" - region: "{{ openshift_aws_region }}" - with_items: "{{ k8s_sg_create.results }}" diff --git a/roles/openshift_aws/tasks/setup_master_group.yml b/roles/openshift_aws/tasks/setup_master_group.yml index 05b68f460..700917ef4 100644 --- a/roles/openshift_aws/tasks/setup_master_group.yml +++ b/roles/openshift_aws/tasks/setup_master_group.yml @@ -8,7 +8,7 @@ msg: "openshift_aws_region={{ openshift_aws_region }}" - name: fetch newly created instances - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: "tag:clusterid": "{{ openshift_aws_clusterid }}" @@ -19,11 +19,13 @@ delay: 3 until: instancesout.instances|length > 0 +- debug: var=instancesout + - name: add new master to masters group add_host: groups: "{{ openshift_aws_masters_groups }}" name: "{{ item.public_dns_name }}" - hostname: "{{ openshift_aws_clusterid }}-master-{{ item.id[:-5] }}" + hostname: "{{ openshift_aws_clusterid }}-master-{{ item.instance_id[:-5] }}" with_items: "{{ instancesout.instances }}" - name: wait for ssh to become available diff --git a/roles/openshift_aws/tasks/setup_scale_group_facts.yml b/roles/openshift_aws/tasks/setup_scale_group_facts.yml index d65fdc2de..14c5246c9 100644 --- a/roles/openshift_aws/tasks/setup_scale_group_facts.yml +++ b/roles/openshift_aws/tasks/setup_scale_group_facts.yml @@ -1,11 +1,15 @@ --- -- name: group scale group nodes - ec2_remote_facts: +- name: fetch all created instances + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: - "{{ {'tag:kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid }}}" + "{{ {'tag:kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid, + 'instance-state-name': 'running'} }}" register: qinstances +# The building of new and current groups is dependent of having a list of the current asgs and the created ones +# that can be found in the variables: openshift_aws_created_asgs, openshift_aws_current_asgs. If these do not exist, we cannot determine which hosts are +# new and which hosts are current. - name: Build new node group add_host: groups: oo_sg_new_nodes @@ -13,10 +17,16 @@ name: "{{ item.public_dns_name }}" hostname: "{{ item.public_dns_name }}" when: - - (item.tags.version | default(False)) == openshift_aws_new_version + - openshift_aws_created_asgs != [] + - "'aws:autoscaling:groupName' in item.tags" + - item.tags['aws:autoscaling:groupName'] in openshift_aws_created_asgs - "'node' in item.tags['host-type']" with_items: "{{ qinstances.instances }}" +- name: dump openshift_aws_current_asgs + debug: + msg: "{{ openshift_aws_current_asgs }}" + - name: Build current node group add_host: groups: oo_sg_current_nodes @@ -24,7 +34,9 @@ name: "{{ item.public_dns_name }}" hostname: "{{ item.public_dns_name }}" when: - - (item.tags.version | default('')) == openshift_aws_current_version + - openshift_aws_current_asgs != [] + - "'aws:autoscaling:groupName' in item.tags" + - item.tags['aws:autoscaling:groupName'] in openshift_aws_current_asgs - "'node' in item.tags['host-type']" with_items: "{{ qinstances.instances }}" diff --git a/roles/openshift_aws/tasks/upgrade_node_group.yml b/roles/openshift_aws/tasks/upgrade_node_group.yml index c3f86f523..4f4730dd6 100644 --- a/roles/openshift_aws/tasks/upgrade_node_group.yml +++ b/roles/openshift_aws/tasks/upgrade_node_group.yml @@ -1,12 +1,22 @@ --- -- fail: - msg: 'Please ensure the current_version and new_version variables are not the same.' +- include_tasks: provision_nodes.yml + vars: + openshift_aws_node_group_upgrade: True when: - - openshift_aws_current_version == openshift_aws_new_version + - openshift_aws_upgrade_provision_nodes | default(True) -- include_tasks: provision_nodes.yml +- debug: var=openshift_aws_current_asgs +- debug: var=openshift_aws_created_asgs + +- name: fail if asg variables aren't set + fail: + msg: "Please ensure that openshift_aws_created_asgs and openshift_aws_current_asgs are defined." + when: + - openshift_aws_created_asgs == [] + - openshift_aws_current_asgs == [] - include_tasks: accept_nodes.yml + when: openshift_aws_upgrade_accept_nodes | default(True) - include_tasks: setup_scale_group_facts.yml diff --git a/roles/openshift_aws/tasks/wait_for_groups.yml b/roles/openshift_aws/tasks/wait_for_groups.yml index 9f1a68a2a..1f4ef3e1c 100644 --- a/roles/openshift_aws/tasks/wait_for_groups.yml +++ b/roles/openshift_aws/tasks/wait_for_groups.yml @@ -1,31 +1,41 @@ --- # The idea here is to wait until all scale groups are at # their desired capacity before continuing. -- name: fetch the scale groups +# This is accomplished with a custom filter_plugin and until clause +- name: "fetch the scale groups" ec2_asg_facts: region: "{{ openshift_aws_region }}" tags: - "{{ {'kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid} }}" + "{{ {'kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid } }}" register: qasg - until: qasg.results | scale_groups_match_capacity | bool + until: qasg | json_query('results[*]') | scale_groups_match_capacity | bool delay: 10 retries: 60 +- debug: var=openshift_aws_created_asgs + +# how do we gaurantee the instances are up? - name: fetch newly created instances - ec2_remote_facts: + ec2_instance_facts: region: "{{ openshift_aws_region }}" filters: "{{ {'tag:kubernetes.io/cluster/' ~ openshift_aws_clusterid: openshift_aws_clusterid, - 'tag:version': openshift_aws_new_version} }}" + 'tag:aws:autoscaling:groupName': item, + 'instance-state-name': 'running'} }}" + with_items: "{{ openshift_aws_created_asgs if openshift_aws_created_asgs != [] else qasg | sum(attribute='results', start=[]) }}" register: instancesout until: instancesout.instances|length > 0 delay: 5 retries: 60 +- name: dump instances + debug: + msg: "{{ instancesout.results | sum(attribute='instances', start=[]) }}" + - name: wait for ssh to become available wait_for: port: 22 host: "{{ item.public_ip_address }}" timeout: 300 search_regex: OpenSSH - with_items: "{{ instancesout.instances }}" + with_items: "{{ instancesout.results | sum(attribute='instances', start=[]) }}" diff --git a/roles/openshift_aws/templates/user_data.j2 b/roles/openshift_aws/templates/user_data.j2 index fe0fe83d4..bda1334cd 100644 --- a/roles/openshift_aws/templates/user_data.j2 +++ b/roles/openshift_aws/templates/user_data.j2 @@ -7,8 +7,8 @@ write_files: owner: 'root:root' permissions: '0640' content: | - openshift_group_type: {{ launch_config_item.key }} -{% if launch_config_item.key != 'master' %} + openshift_group_type: {{ openshift_aws_node_group.group }} +{% if openshift_aws_node_group.group != 'master' %} - path: /etc/origin/node/bootstrap.kubeconfig owner: 'root:root' permissions: '0640' @@ -19,7 +19,7 @@ runcmd: {% if openshift_aws_node_run_bootstrap_startup %} - [ ansible-playbook, /root/openshift_bootstrap/bootstrap.yml] {% endif %} -{% if launch_config_item.key != 'master' %} +{% if openshift_aws_node_group.group != 'master' %} - [ systemctl, restart, NetworkManager] - [ systemctl, enable, {% if openshift_deployment_type == 'openshift-enterprise' %}atomic-openshift{% else %}origin{% endif %}-node] - [ systemctl, start, {% if openshift_deployment_type == 'openshift-enterprise' %}atomic-openshift{% else %}origin{% endif %}-node] diff --git a/roles/openshift_ca/meta/main.yml b/roles/openshift_ca/meta/main.yml index f8b784a63..81b49ce60 100644 --- a/roles/openshift_ca/meta/main.yml +++ b/roles/openshift_ca/meta/main.yml @@ -14,3 +14,4 @@ galaxy_info: - system dependencies: - role: openshift_cli +- role: openshift_facts diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py index 520c00340..a10ba9310 100755 --- a/roles/openshift_facts/library/openshift_facts.py +++ b/roles/openshift_facts/library/openshift_facts.py @@ -458,7 +458,6 @@ def set_url_facts_if_unset(facts): etcd_urls = [] if etcd_hosts != '': facts['master']['etcd_port'] = ports['etcd'] - facts['master']['embedded_etcd'] = False for host in etcd_hosts: etcd_urls.append(format_url(use_ssl['etcd'], host, ports['etcd'])) @@ -1595,7 +1594,7 @@ class OpenShiftFacts(object): console_port='8443', etcd_use_ssl=True, etcd_hosts='', etcd_port='4001', portal_net='172.30.0.0/16', - embedded_etcd=True, embedded_kube=True, + embedded_kube=True, embedded_dns=True, bind_addr='0.0.0.0', session_max_seconds=3600, diff --git a/roles/openshift_management/meta/main.yml b/roles/openshift_management/meta/main.yml index 07ad51126..9f19704a8 100644 --- a/roles/openshift_management/meta/main.yml +++ b/roles/openshift_management/meta/main.yml @@ -16,3 +16,4 @@ galaxy_info: dependencies: - role: lib_openshift - role: lib_utils +- role: openshift_facts diff --git a/roles/openshift_master/templates/master.yaml.v1.j2 b/roles/openshift_master/templates/master.yaml.v1.j2 index 92668b227..f1a76e5f5 100644 --- a/roles/openshift_master/templates/master.yaml.v1.j2 +++ b/roles/openshift_master/templates/master.yaml.v1.j2 @@ -69,29 +69,13 @@ dnsConfig: bindNetwork: tcp4 {% endif %} etcdClientInfo: - ca: {{ "ca-bundle.crt" if (openshift.master.embedded_etcd | bool) else "master.etcd-ca.crt" }} + ca: master.etcd-ca.crt certFile: master.etcd-client.crt keyFile: master.etcd-client.key urls: {% for etcd_url in openshift.master.etcd_urls %} - {{ etcd_url }} {% endfor %} -{% if openshift.master.embedded_etcd | bool %} -etcdConfig: - address: {{ openshift.common.hostname }}:{{ openshift.master.etcd_port }} - peerAddress: {{ openshift.common.hostname }}:7001 - peerServingInfo: - bindAddress: {{ openshift.master.bind_addr }}:7001 - certFile: etcd.server.crt - clientCA: ca-bundle.crt - keyFile: etcd.server.key - servingInfo: - bindAddress: {{ openshift.master.bind_addr }}:{{ openshift.master.etcd_port }} - certFile: etcd.server.crt - clientCA: ca-bundle.crt - keyFile: etcd.server.key - storageDirectory: {{ r_openshift_master_data_dir }}/openshift.local.etcd -{% endif %} etcdStorageConfig: kubernetesStoragePrefix: kubernetes.io kubernetesStorageVersion: v1 diff --git a/roles/openshift_master_facts/tasks/main.yml b/roles/openshift_master_facts/tasks/main.yml index 0cb87dcaa..418dcba67 100644 --- a/roles/openshift_master_facts/tasks/main.yml +++ b/roles/openshift_master_facts/tasks/main.yml @@ -45,7 +45,6 @@ etcd_port: "{{ openshift_master_etcd_port | default(None) }}" etcd_use_ssl: "{{ openshift_master_etcd_use_ssl | default(None) }}" etcd_urls: "{{ openshift_master_etcd_urls | default(None) }}" - embedded_etcd: "{{ openshift_master_embedded_etcd | default(None) }}" embedded_kube: "{{ openshift_master_embedded_kube | default(None) }}" embedded_dns: "{{ openshift_master_embedded_dns | default(None) }}" bind_addr: "{{ openshift_master_bind_addr | default(None) }}" diff --git a/roles/openshift_openstack/defaults/main.yml b/roles/openshift_openstack/defaults/main.yml index 929b76f54..65a647b8f 100644 --- a/roles/openshift_openstack/defaults/main.yml +++ b/roles/openshift_openstack/defaults/main.yml @@ -44,6 +44,9 @@ openshift_openstack_container_storage_setup: # populate-dns openshift_openstack_dns_records_add: [] +openshift_openstack_public_hostname_suffix: "" +openshift_openstack_private_hostname_suffix: "" +openshift_openstack_public_dns_domain: "example.com" openshift_openstack_full_dns_domain: "{{ (openshift_openstack_clusterid|trim == '') | ternary(openshift_openstack_public_dns_domain, openshift_openstack_clusterid + '.' + openshift_openstack_public_dns_domain) }}" openshift_openstack_app_subdomain: "apps" diff --git a/roles/openshift_openstack/tasks/populate-dns.yml b/roles/openshift_openstack/tasks/populate-dns.yml index eae4967f7..cf2ead5c3 100644 --- a/roles/openshift_openstack/tasks/populate-dns.yml +++ b/roles/openshift_openstack/tasks/populate-dns.yml @@ -1,7 +1,7 @@ --- - name: "Generate list of private A records" set_fact: - private_records: "{{ private_records | default([]) + [ { 'type': 'A', 'hostname': hostvars[item]['ansible_hostname'], 'ip': hostvars[item]['private_v4'] } ] }}" + private_records: "{{ private_records | default([]) + [ { 'type': 'A', 'hostname': hostvars[item]['ansible_hostname'] + openshift_openstack_private_hostname_suffix, 'ip': hostvars[item]['private_v4'] } ] }}" with_items: "{{ groups['cluster_hosts'] }}" - name: "Add wildcard records to the private A records for infrahosts" @@ -48,7 +48,7 @@ - name: "Generate list of public A records" set_fact: - public_records: "{{ public_records | default([]) + [ { 'type': 'A', 'hostname': hostvars[item]['ansible_hostname'], 'ip': hostvars[item]['public_v4'] } ] }}" + public_records: "{{ public_records | default([]) + [ { 'type': 'A', 'hostname': hostvars[item]['ansible_hostname'] + openshift_openstack_public_hostname_suffix, 'ip': hostvars[item]['public_v4'] } ] }}" with_items: "{{ groups['cluster_hosts'] }}" when: hostvars[item]['public_v4'] is defined |