Jim Rigsbee
2019-09-19 cd9d766364ad17c16ea706be03d33690234556d4
WIP: restructure how windows hosts are handled
1. Created inventories separately for windows for PSRP vs. WINRM
2. Fixed issues with include_vars not working for windows hosts using PSRP
3. Fixed issues found in testing skylight with PSRP and new host configuration for windows
2 files added
19 files modified
550 ■■■■ changed files
ansible/cloud_providers/ec2_infrastructure_deployment.yml 19 ●●●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/env_vars.yml 28 ●●●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/files/cloud_providers/ec2_cloud_template.j2 6 ●●●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/files/hosts_template.j2 2 ●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/post_software.yml 19 ●●●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/pre_infra.yml 1 ●●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/pre_software.yml 22 ●●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/software.yml 2 ●●● patch | view | raw | blame | history
ansible/configs/ansible-skylight/templates/win_ec2_userdata.j2 4 ●●● patch | view | raw | blame | history
ansible/include_vars.yml 161 ●●●●● patch | view | raw | blame | history
ansible/roles/infra-common-ssh-config-generate/tasks/main.yml 1 ●●●● patch | view | raw | blame | history
ansible/roles/infra-ec2-create-inventory/defaults/main.yml 2 ●●●●● patch | view | raw | blame | history
ansible/roles/infra-ec2-create-inventory/tasks/main.yml 97 ●●●●● patch | view | raw | blame | history
ansible/roles/set-repositories/tasks/rhn-repos.yml 22 ●●●●● patch | view | raw | blame | history
ansible/roles/skylight-linux-common/tasks/main.yml 8 ●●●● patch | view | raw | blame | history
ansible/roles/skylight-windows-ad/tasks/main.yml 36 ●●●● patch | view | raw | blame | history
ansible/roles/skylight-windows-common/library/win_dns_searchsuffix.ps1 48 ●●●●● patch | view | raw | blame | history
ansible/roles/skylight-windows-common/tasks/main.yml 11 ●●●●● patch | view | raw | blame | history
ansible/roles/skylight-windows-workstation/tasks/adv_lab.yml 4 ●●●● patch | view | raw | blame | history
ansible/roles/skylight-windows-workstation/tasks/git_lab.yml 4 ●●●● patch | view | raw | blame | history
ansible/roles/skylight-windows-workstation/tasks/main.yml 53 ●●●●● patch | view | raw | blame | history
ansible/cloud_providers/ec2_infrastructure_deployment.yml
@@ -62,6 +62,12 @@
      import_role:
        name: infra-common-ssh-config-generate
    - name: Start a SSH/Socks proxy for Windows proxying through bastion
      shell: |
        mkdir -p ~/.ssh/cp
        ssh -i {{ ssh_key | default(infra_ssh_key) | default(ansible_ssh_private_key_file) | default(default_key_name)}} -o "ControlMaster=auto" -o "ControlPersist=no" -o "ControlPath=~/.ssh/cp/ssh-%r@%h:%p" -o "StrictHostKeyChecking=no" -CfNq -D 127.0.0.1:1234 -p 22 {{hostvars[bastion_hostname].ansible_user}}@{{hostvars[bastion_hostname].public_dns_name}}
      when: win_connect_method | d('winrm') == 'psrp'
# include global vars again, this time for all hosts now that the inventory is built
- import_playbook: ../include_vars.yml
  tags:
@@ -104,19 +110,6 @@
    - step001
    - step001.4
  tasks:
    - name: set facts for remote access
      tags:
        - create_inventory
      set_fact:
        ansible_become: false
        ansible_connection: winrm
        ansible_host: "{{ public_dns_name }}"
        ansible_password: "{{ hostvars['localhost'].windows_password | default(hostvars['localhost'].generated_windows_password) }}"
        ansible_port: 5986
        ansible_user: Administrator
        ansible_winrm_server_cert_validation: ignore
        aws_region_final: "{{hostvars['localhost'].aws_region_final}}"
    - name: Run infra-ec2-wait_for_windows_hosts Role
      import_role:
        name: infra-ec2-wait_for_windows_hosts
ansible/configs/ansible-skylight/env_vars.yml
@@ -38,6 +38,7 @@
env_authorized_key: "{{guid}}key"
ansible_ssh_private_key_file: ~/.ssh/{{key_name}}
set_env_authorized_key: true
win_connect_method: psrp
### AWS EC2 Environment settings
@@ -230,6 +231,7 @@
        value: "towers"
      - key: "ostype"
        value: "linux"
    #TODO is this needed? it doesn't work like this
    # UserData: |
    #      UserData:
    #             hostname: tower
@@ -263,20 +265,9 @@
    UserData: "{{ lookup('template', '../configs/{{ env_type }}/templates/win_ec2_userdata.j2') }}"
    tags:
      - key: "AnsibleGroup"
        value: "activedirectories,windows"
        value: "activedirectories"
      - key: "ostype"
        value: "windows"
    # UserData: |
    #      UserData:
    #             "Fn::Base64":
    #                "Fn::Join":
    #                  - ""
    #                  - - "<powershell>\n"
    #                    - "$admin = [adsi]('WinNT://./administrator, user')\n"
    #                    - "$admin.PSBase.Invoke('SetPassword', '{{windows_password}}')\n"
    #                    - "$scriptPath=((New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1'))\n"
    #                    - "Invoke-Command -ScriptBlock ([scriptblock]::Create($scriptPath)) -ArgumentList '-skipNetworkProfileCheck'\n"
    #                    - "</powershell>"
  - name: "win"
    count: "{{windows_instance_count}}"
@@ -289,7 +280,7 @@
    UserData: "{{ lookup('template', '../configs/{{ env_type }}/templates/win_ec2_userdata.j2') }}"
    tags:
      - key: "AnsibleGroup"
        value: "windows"
        value: "windows_servers"
      - key: "ostype"
        value: "windows"
@@ -304,7 +295,7 @@
    UserData: "{{ lookup('template', '../configs/{{ env_type }}/templates/win_ec2_userdata.j2') }}"
    tags:
      - key: "AnsibleGroup"
        value: "workstations,windows"
        value: "workstations,windows_servers"
      - key: "ostype"
        value: "windows"
@@ -312,8 +303,10 @@
###### VARIABLES YOU SHOULD ***NOT*** CONFIGURE FOR YOUR DEPLOYMENT
###### You can, but you usually wouldn't need to.
ansible_user: ec2-user
remote_user: ec2-user
# The following interfere with Windows servers which use Administrator
#ansible_user: ec2-user
#remote_user: ec2-user
common_packages:
  - python
@@ -376,3 +369,6 @@
# Email configuration.
gitlab_email_enabled: "false"
gitlab_smtp_enable: "false"
git_lab: false
advanced_lab: false
ansible/configs/ansible-skylight/files/cloud_providers/ec2_cloud_template.j2
@@ -233,12 +233,12 @@
      - Key: Name
        Value: {{course_name}}-{{guid}}-{{instance['name']}}
      - Key: internaldns
        Value: {{instance['name']}}
        Value: {{instance['name']}}.{{chomped_zone_internal_dns}}
{% else %}
      - Key: Name
        Value: {{course_name}}-{{guid}}-{{instance['name']}}{{instancecount.index}}
      - Key: internaldns
        Value: {{instance['name']}}{{loop.index}}
        Value: {{instance['name']}}{{loop.index}}.{{chomped_zone_internal_dns}}
{% endif %}
      - Key: "owner"
        Value: "{{ email | default('unknownuser') }}"
@@ -246,6 +246,8 @@
        Value: "{{project_tag}}"
      - Key: "{{project_tag}}"
        Value: "{{ instance['name'] }}"
      - Key: "instance_name"
        Value: "{{ instance['name'] }}"
      - Key: "env_type"
        Value: "{{ env_type }}"
      - Key: "guid"
ansible/configs/ansible-skylight/files/hosts_template.j2
@@ -47,7 +47,7 @@
{%   elif "win2" in host %}
{{ host }} ansible_host={{ hostvars[host].private_ip_address }} ansible_user={{ hostvars[host].ansible_user }} ansible_password="{{ windows_password }}" private_ip={{ hostvars[host].private_ip_address }}
{%   elif "workstation" in host %}
{{ host }} ansible_host={{ hostvars[host].private_ip_address }} ansible_user={{ hostvars[host].ansible_user }} ansible_password="{{ windows_password }}" private_ip={{ hostvars[host].private_ip_address }}
{{ host }} ansible_host={{ hostvars[host].private_ip_address }} ansible_user={{ hostvars[host].ansible_user }} ansible_password="{{ workstation_password }}" private_ip={{ hostvars[host].private_ip_address }}
{%   endif %}
{% endfor %}
ansible/configs/ansible-skylight/post_software.yml
@@ -6,6 +6,25 @@
    - debug:
        msg: "Post-Software tasks Started"
- name: Cleanup Windows Proxying
  hosts: localhost
  connection: local
  gather_facts: false
  become: false
  tasks:
    - name: Stop SSH/Socks proxy for Windows proxying through bastion
      shell: |
        ssh -i {{ ssh_key | default(infra_ssh_key) | default(ansible_ssh_private_key_file) | default(default_key_name)}} -o "ControlPath=~/.ssh/cp/ssh-%r@%h:%p" -O stop -p 22 {{hostvars[bastion_hostname].ansible_user}}@{{hostvars[bastion_hostname].public_dns_name}}
      when: win_connect_method | d('winrm') == 'psrp'
- name: Copy files to workstation
  hosts: workstations
  tasks:
    - name: Copy Ansible Inventory for this environment
      win_copy:
        src: "{{output_dir}}/hosts-{{ env_type }}-{{ guid }}"
        dest: "C:\\inventory.ini"
- name: PostSoftware flight-check
  hosts: localhost
  connection: local
ansible/configs/ansible-skylight/pre_infra.yml
@@ -43,3 +43,4 @@
        content: "{{ windows_password | default(generated_windows_password) }}"
        dest: "{{output_dir}}/{{ env_type }}_{{guid}}_windows_password.txt"
        mode: 0600
ansible/configs/ansible-skylight/pre_software.yml
@@ -25,7 +25,7 @@
    - step004
    - common_tasks
  roles:
    - { role: "set-repositories", when: 'repo_method is defined' }
#    - { role: "set-repositories", when: 'repo_method is defined' }
    - { role: "common", when: 'install_common' }
    - { role: "set_env_authorized_key", when: 'set_env_authorized_key' }
@@ -38,16 +38,16 @@
    - step004
    - bastion_tasks
- name: Inject and configure FTL on bastion as grader host
  hosts: bastions
  become: true
  tasks:
    - name: Setup FTL
      include_role:
        name: ftl-injector
  tags:
    - step004
    - ftl-injector
# - name: Inject and configure FTL on bastion as grader host
#   hosts: bastions
#   become: true
#   tasks:
#     - name: Setup FTL
#       include_role:
#         name: ftl-injector
#   tags:
#     - step004
#     - ftl-injector
- name: Configure windows machines
  hosts:
ansible/configs/ansible-skylight/software.yml
@@ -16,7 +16,7 @@
    - skylight-windows-ad
- name: Step 002 software - Configure Windows Servers
  hosts: windows
  hosts: windows_servers
  gather_facts: true
  tags:
    - windows-servers
ansible/configs/ansible-skylight/templates/win_ec2_userdata.j2
@@ -4,7 +4,9 @@
          - ""
          - - "<powershell>\n"
            - "Get-ScheduledTask *ngen* | Disable-ScheduledTask\n"
            - "reg add 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update' /v AUOptions /t REG_DWORD /d 1 /f net stop wuauserv net start wuauserv\n"
            - "reg add 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update' /v AUOptions /t REG_DWORD /d 1 /f\n"
            - "net stop wuauserv\n"
            - "net start wuauserv\n"
            - "Set-MpPreference -DisableRealtimeMonitoring $true\n"
            - "$admin = [adsi]('WinNT://./administrator, user')\n"
            - "$admin.PSBase.Invoke('SetPassword', '{{windows_password}}')\n"
ansible/include_vars.yml
@@ -1,58 +1,115 @@
---
- hosts:
    - localhost
    - all
  connection: local
  gather_facts: no
  tags: include_vars
  tasks:
    - name: Set output_dir for all hosts
      set_fact:
        output_dir: "{{ hostvars.localhost.output_dir }}"
      when: hostvars.localhost.output_dir is defined
   - localhost
   - all
 connection: local
 gather_facts: no
 tags: include_vars
 tasks:
   - name: Set output_dir for all hosts
     set_fact:
       output_dir: "{{ hostvars.localhost.output_dir }}"
     when: hostvars.localhost.output_dir is defined
    - name: Stat default variables files (both yaml/yml extensions) [Linux]
      block:
        - name: stat environment variables
          vars:
            find_me:
              # Global default vars related to the cloud provider
              - cloud_providers/{{ cloud_provider }}_default_vars
              # Legacy env_vars.yml (replaced by default_vars.yml)
              - configs/{{ env_type }}/env_vars
              # Default vars of the config
              - configs/{{ env_type }}/default_vars
              # Default vars of the config, specific to a cloud provider
              - configs/{{ env_type }}/default_vars.{{ cloud_provider }}
              - configs/{{ env_type }}/default_vars_{{ cloud_provider }}
              # Lecacy secret vars file.
              - configs/{{ env_type }}/env_secret_vars
            extensions:
              - yaml
              - yml
          stat:
            path: "{{ item[0] ~ '.' ~ item[1] }}"
          loop: "{{ find_me | product(extensions) | list }}"
          register: rstat_varfiles
    - name: Stat default variables files (both yaml/yml extensions)
      vars:
        find_me:
          # Global default vars related to the cloud provider
          - cloud_providers/{{ cloud_provider }}_default_vars
          # Legacy env_vars.yml (replaced by default_vars.yml)
          - configs/{{ env_type }}/env_vars
          # Default vars of the config
          - configs/{{ env_type }}/default_vars
          # Default vars of the config, specific to a cloud provider
          - configs/{{ env_type }}/default_vars.{{ cloud_provider }}
          - configs/{{ env_type }}/default_vars_{{ cloud_provider }}
          # Lecacy secret vars file.
          - configs/{{ env_type }}/env_secret_vars
        extensions:
          - yaml
          - yml
      stat:
        path: "{{ item[0] ~ '.' ~ item[1] }}"
      loop: "{{ find_me | product(extensions) | list }}"
      register: rstat_varfiles
        - name: Stat variables files
          vars:
            find_me:
              # secret file path passed as extra-var
              - "{{ secret_file | d('/secret/file/not/passed') }}"
          stat:
            path: "{{ item }}"
          loop: "{{ find_me }}"
          register: rstat2_varfiles
    - name: Stat variables files
      vars:
        find_me:
          # secret file path passed as extra-var
          - "{{ secret_file | d('/secret/file/not/passed') }}"
      stat:
        path: "{{ item }}"
      loop: "{{ find_me }}"
      register: rstat2_varfiles
        - name: Include variables files
          include_vars:
            file: "{{ item.stat.path }}"
          when:
            - item is not skipped
            - item.stat.exists
          loop: "{{ rstat_varfiles.results + rstat2_varfiles.results }}"
          loop_control:
            label: >-
              {{ (
                item.stat.path
                | default('skipped')
              ) if 'stat' in item else item }}
      when: hostvars[inventory_hostname].ostype | d('linux') != 'windows'
    - name: Include variables files
      include_vars:
        file: "{{ item.stat.path }}"
    - name: Stat default variables files (both yaml/yml extensions) [Windows]
      block:
        - name: stat environment variables
          vars:
            find_me:
              # Global default vars related to the cloud provider
              - cloud_providers/{{ cloud_provider }}_default_vars
              # Legacy env_vars.yml (replaced by default_vars.yml)
              - configs/{{ env_type }}/env_vars
              # Default vars of the config
              - configs/{{ env_type }}/default_vars
              # Default vars of the config, specific to a cloud provider
              - configs/{{ env_type }}/default_vars.{{ cloud_provider }}
              - configs/{{ env_type }}/default_vars_{{ cloud_provider }}
              # Lecacy secret vars file.
              - configs/{{ env_type }}/env_secret_vars
            extensions:
              - yaml
              - yml
          stat:
            path: "{{ item[0] ~ '.' ~ item[1] }}"
          loop: "{{ find_me | product(extensions) | list }}"
          register: rstat_varfiles
        - name: Stat variables files
          vars:
            find_me:
              # secret file path passed as extra-var
              - "{{ secret_file | d('/secret/file/not/passed') }}"
          stat:
            path: "{{ item }}"
          loop: "{{ find_me }}"
          register: rstat2_varfiles
        - name: Include variables files
          include_vars:
            file: "{{ item.stat.path }}"
          when:
            - item is not skipped
            - item.stat.exists
          loop: "{{ rstat_varfiles.results + rstat2_varfiles.results }}"
          loop_control:
            label: >-
              {{ (
                item.stat.path
                | default('skipped')
              ) if 'stat' in item else item }}
      when:
        - item is not skipped
        - item.stat.exists
      loop: "{{ rstat_varfiles.results + rstat2_varfiles.results }}"
      loop_control:
        label: >-
          {{ (
            item.stat.path
            | default('skipped')
          ) if 'stat' in item else item }}
        - groups['windows'] is defined
        - inventory_hostname in groups['windows']
      delegate_to: localhost
ansible/roles/infra-common-ssh-config-generate/tasks/main.yml
@@ -79,6 +79,7 @@
  when:
    - item not in [bastion_hostname, 'localhost', '127.0.0.1']
    - item != hostvars[item].bastion
    - hostvars[item].ostype == 'linux'
  with_items: "{{ groups['all'] }}"
  tags:
    - bastion_proxy_config_hosts
ansible/roles/infra-ec2-create-inventory/defaults/main.yml
New file
@@ -0,0 +1,2 @@
---
win_connect_method: winrm
ansible/roles/infra-ec2-create-inventory/tasks/main.yml
@@ -49,7 +49,8 @@
#     var: "{{ item }}"
#   with_items: "{{ec2_facts['instances']}}"
- add_host:
- name: Add Linux hosts
  add_host:
    name: "{{item.tags.internaldns | default(item.private_dns_name)}}"
    shortname: "{{item.tags.Name | default(item.private_dns_name)}}"
    groups:
@@ -76,7 +77,99 @@
    image_id: "{{item['image_id']}}"
    ansible_ssh_extra_args: "-o StrictHostKeyChecking=no"
    bastion: "{{ local_bastion | default('') }}"
  when: item.state.name != 'terminated'
    ostype: "{{item.tags.ostype | default('linux')}}"
    instance_name: "{{item.tags.instance_name  | d('') }}"
  when:
    - item.state.name != 'terminated'
    - item.tags.ostype | d('linux') == 'linux'
  with_items: "{{ec2_facts['instances']}}"
  loop_control:
    label: "{{item.tags.internaldns | default(item.private_dns_name)}}"
  tags:
    - create_inventory
    - must
- name: Add Windows hosts - winrm
  add_host:
    name: "{{item.tags.internaldns | default(item.private_dns_name)}}"
    shortname: "{{item.tags.Name | default(item.private_dns_name)}}"
    groups:
      - "tag_Project_{{stack_tag}}"
      - "tag_{{stack_tag}}_{{item['tags'][project_tag] | default('unknowns')}}"
      - "tag_{{stack_tag}}_ostype_{{item['tags'][project_tag_ostype] | default('unknown')}}"
      - "{{item.tags.ostype | default('unknowns')}}"
      - "{{item['tags'][project_tag_ostype] | default('unknowns')}}"
      - "{{ 'newnodes' if (item.tags.newnode|d()|bool) else 'all'}}"
    ansible_user: Administrator
    remote_user: Administrator
    ansible_connection: winrm
    ansible_password: "{{ hostvars['localhost'].windows_password | default(hostvars['localhost'].generated_windows_password) }}"
    ansible_port: 5986
    ansible_winrm_server_cert_validation: ignore
    key_name: "{{item['key_name']}}"
    state: "{{item['state']}}"
    internaldns: "{{item.tags.internaldns | default(item.private_dns_name)}}"
    isolated: "{{item.tags.isolated | default(false)}}"
    instance_id: "{{ item.instance_id }}"
    region: "{{ aws_region_final | default(aws_region) | default(region) | default('us-east-1')}}"
    public_dns_name: "{{item['public_dns_name']}}"
    private_dns_name: "{{item['private_dns_name']}}"
    private_ip_address: "{{item['private_ip_address']}}"
    public_ip_address: "{{item['public_ip_address'] | d('') }}"
    placement: "{{item['placement']['availability_zone']}}"
    image_id: "{{item['image_id']}}"
    bastion: "{{ local_bastion | default('') }}"
    ostype: "{{item.tags.ostype | default('windows') }}"
    instance_name: "{{item.tags.instance_name | d('') }}"
  when:
    - item.state.name != 'terminated'
    - item.tags.ostype | d('linux') == 'windows'
    - win_connect_method == 'winrm'
  with_items: "{{ec2_facts['instances']}}"
  loop_control:
    label: "{{item.tags.internaldns | default(item.private_dns_name)}}"
  tags:
    - create_inventory
    - must
- name: Add Windows Hosts - psrp
  add_host:
    name: "{{item.tags.internaldns | default(item.private_dns_name)}}"
    shortname: "{{item.tags.Name | default(item.private_dns_name)}}"
    groups:
      - "tag_Project_{{stack_tag}}"
      - "tag_{{stack_tag}}_{{item['tags'][project_tag] | default('unknowns')}}"
      - "tag_{{stack_tag}}_ostype_{{item['tags'][project_tag_ostype] | default('unknown')}}"
      - "{{item.tags.ostype | default('unknowns')}}"
      - "{{item['tags'][project_tag_ostype] | default('unknowns')}}"
      - "{{ 'newnodes' if (item.tags.newnode|d()|bool) else 'all'}}"
    ansible_user: Administrator
    remote_user: Administrator
    ansible_connection: psrp
    ansible_password: "{{ hostvars['localhost'].windows_password | default(hostvars['localhost'].generated_windows_password) }}"
    ansible_psrp_protocol: https
    ansible_psrp_auth: basic
    ansible_psrp_cert_validation: ignore
    ansible_psrp_proxy: socks5h://localhost:1234
    key_name: "{{item['key_name']}}"
    state: "{{item['state']}}"
    internaldns: "{{item.tags.internaldns | default(item.private_dns_name)}}"
    isolated: "{{item.tags.isolated | default(false)}}"
    instance_id: "{{ item.instance_id }}"
    region: "{{ aws_region_final | default(aws_region) | default(region) | default('us-east-1')}}"
    public_dns_name: "{{item['public_dns_name']}}"
    private_dns_name: "{{item['private_dns_name']}}"
    private_ip_address: "{{item['private_ip_address']}}"
    public_ip_address: "{{item['public_ip_address'] | d('') }}"
    placement: "{{item['placement']['availability_zone']}}"
    image_id: "{{item['image_id']}}"
    bastion: "{{ local_bastion | default('') }}"
    ostype: "{{item.tags.ostype | default('windows') }}"
    instance_name: "{{item.tags.instance_name | d('') }}"
  when:
    - item.state.name != 'terminated'
    - item.tags.ostype | d('linux') == 'windows'
    - win_connect_method == 'psrp'
  with_items: "{{ec2_facts['instances']}}"
  loop_control:
    label: "{{item.tags.internaldns | default(item.private_dns_name)}}"
ansible/roles/set-repositories/tasks/rhn-repos.yml
@@ -18,7 +18,27 @@
    pool_ids: "{{ rhsm_pool_ids }}"
    auto_attach: false
- name: "Run 'subscription-manager to disable/enable repos"
# TODO: should take pool ids from a var
- name: get product pool id
  shell: /usr/bin/subscription-manager list --all --available --matches="*{{rhn_pool_id_string}}*" | awk '/Pool ID/ {print $3}' | head -1
  # command: subscription-manager list --all --available --matches="OpenShift Container Platform" | awk '/Pool ID/ {print $3}' | head -1
  register: pool_id
  until: pool_id is succeeded
  retries: 10
  delay: 5
- name: attach host to subscription pool
  shell: /usr/bin/subscription-manager attach --pool={{ pool_id.stdout }}
  register: task_result
  until: task_result.rc == 0
  retries: 10
  delay: 5
- name: disable repos for server
  command: subscription-manager repos --disable "*"
  when: disable_default_repos | d(false)
- name: "Run 'subscription-manager to enable repos"
  command: >-
    subscription-manager repos {% for repo in rhel_repos %}
    --enable={{ repo }}
ansible/roles/skylight-linux-common/tasks/main.yml
@@ -7,7 +7,7 @@
- name: Set hostname
  hostname:
    name: "{{ inventory_hostname }}.{{ dns_domain_name }}"
    name: "{{ hostvars[inventory_hostname].instance_name}}.{{ dns_domain_name }}"
- name: Create dhclient.conf
  file:
@@ -17,11 +17,15 @@
    group: root
    mode: 0644
- name: Discover domain controller host
  set_fact:
    dc_host: "{{groups['activedirectories'][0]}}"
- name: Set custom DNS server
  blockinfile:
    dest: /etc/dhcp/dhclient.conf
    block: |
      prepend domain-name-servers {{ hostvars['windc'].private_ip_address }};
      prepend domain-name-servers {{ hostvars[dc_host].private_ip_address }};
      prepend domain-search "{{ dns_domain_name }}", "ec2.internal";
    state: present
  register: dnschange
ansible/roles/skylight-windows-ad/tasks/main.yml
@@ -9,7 +9,7 @@
- name: Set hostname
  win_hostname:
    name: "{{ inventory_hostname }}"
    name: "{{ hostvars[inventory_hostname].instance_name }}"
  register: win_hostname
- name: Reboot if required
@@ -63,33 +63,17 @@
  until: reverse is not failed
  retries: 100
- name: Create DNS A record for gitlab
- name: Create DNS A records
  win_ad_dnsrecord:
    hostname: gitlab
    hostname: "{{ hostvars[item]['instance_name'] }}"
    zone: "{{ dns_domain_name }}"
    ipaddr: "{{ hostvars['gitlab']['private_ip_address'] }}"
    ipaddr: "{{ hostvars[item]['private_ip_address'] }}"
    state: present
- name: Create DNS A record for Tower
  win_ad_dnsrecord:
    hostname: tower
    zone: "{{ dns_domain_name }}"
    ipaddr: "{{ hostvars['tower']['private_ip_address'] }}"
    state: present
- name: Create DNS A record for Win1
  win_ad_dnsrecord:
    hostname: win1
    zone: "{{ dns_domain_name }}"
    ipaddr: "{{ hostvars['win1']['private_ip_address'] }}"
    state: present
- name: Create DNS A record for Win2
  win_ad_dnsrecord:
    hostname: win2
    zone: "{{ dns_domain_name }}"
    ipaddr: "{{ hostvars['win2']['private_ip_address'] }}"
    state: present
  with_items:
    - "gitlab.{{ chomped_zone_internal_dns }}"
    - "tower.{{ chomped_zone_internal_dns }}"
    - "win1.{{ chomped_zone_internal_dns }}"
    - "win2.{{ chomped_zone_internal_dns }}"
#TODO: fix adding this group to administrators, s/b regular users
- name: Add windows group
@@ -131,7 +115,7 @@
    company: Training
    email: "{{ user_prefix }}@{{ dns_domain_name }}"
- name: Set DNS search string
- name: Set DNS search string
  win_dns_searchsuffix:
    suffixes:
      - "{{ dns_domain_name }}"
ansible/roles/skylight-windows-common/library/win_dns_searchsuffix.ps1
New file
@@ -0,0 +1,48 @@
#!powershell
# This file is part of Ansible
#
# Copyright 2018, Jimmy Conner <jconner@redhat.com>
#
# 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/>.
# WANT_JSON
# POWERSHELL_COMMON
$params = Parse-Args $args -supports_check_mode $true
$suffixes = (Get-AnsibleParam -obj $params -name "suffixes" -type "list" -failifempty $true) -join ","
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
$result = @{
    changed = $false
    msg = ""
}
try {
    $current = ((Get-DnsClientGlobalSetting | Select SuffixSearchList).SuffixSearchList) -join ","
    if ($suffixes -eq $current) {
        $result.msg = "Suffixes are present"
    } else {
        if (-not $check_mode) {
            Set-DnsClientGlobalSetting -SuffixSearchList $suffixes
        }
        $result.changed = $true
        $result.msg = "Updated Suffixes: Original: ($current) -- New: ($suffixes)"
    }
}
catch {
    Fail-Json $result $_.Exception.Message
}
Exit-Json $result
ansible/roles/skylight-windows-common/tasks/main.yml
@@ -1,19 +1,23 @@
---
- name: Discover domain controller host
  set_fact:
    dc_host: "{{groups['activedirectories'][0]}}"
- name: Add domain controller private IP as DNS server
  win_dns_client:
    adapter_names: "*"
    ipv4_addresses: "{{ hostvars['windc']['private_ip_address'] }}"
    ipv4_addresses: "{{ hostvars[dc_host]['private_ip_address'] }}"
- name: Set hostname
  win_hostname:
    name: "{{ inventory_hostname }}"
    name: "{{ hostvars[inventory_hostname].instance_name }}"
  register: win_hostname
- name: Reboot if required
  win_reboot:
  when: win_hostname.reboot_required
- name: Set DNS search string to {{ dns_domain_name }}
- name: Set DNS search suffix to {{ dns_domain }}
  win_dns_searchsuffix:
    suffixes:
      - "{{ dns_domain_name }}"
@@ -46,7 +50,6 @@
      win_reboot:
      when: windomain.reboot_required
#TODO: make group part of regular users?
    - name: Add Ansible group to a local Administrators
      win_group_membership:
        name: Administrators
ansible/roles/skylight-windows-workstation/tasks/adv_lab.yml
@@ -9,5 +9,5 @@
      icon: '%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe,0'
  become: yes
  become_user: "{{ dns_domain_name_short }}\\{{ user }}"
  become_method: runas
  become_user: "{{ dns_domain_name_short }}\\{{ user_prefix }}"
  become_method: runas
ansible/roles/skylight-windows-workstation/tasks/git_lab.yml
@@ -9,5 +9,5 @@
      icon: '%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe,0'
  become: yes
  become_user: "{{ dns_domain_name_short }}\\{{ user }}"
  become_method: runas
  become_user: "{{ dns_domain_name_short }}\\{{ user_prefix }}"
  become_method: runas
ansible/roles/skylight-windows-workstation/tasks/main.yml
@@ -1,23 +1,33 @@
---
# RM: This is removed at a later stage - for now this allows the student
# user to configure Git. I tried many things but could not find a clean
# workaround that would properly configure Git for the student user.
# After many back and forth, I decided to leave the default settings that
# were known to work and decided to remove the group from admin at the
# end. See the end of file for the entry that does that.
- name: Add Ansible group to local Administrators group (temporary)
  win_group_membership:
    name: Administrators
    members:
    - "{{ dns_domain_name_short }}\\Ansible Users"
- name: Change workstation administrator password
  win_user:
    account_locked: no
    name: Administrator
    password: "{{ workstation_password }}"
    password_expired: no
    update_password: always
    password_never_expires: yes
    state: present
- name: Change ansible password for this server
  set_fact:
    ansible_password: "{{ workstation_password }}"
# TODO figure out why this doesn't work
# JR: Ansible just ignores this and runs as Administrator but when I set
#     "become" vars via set_fact it uses them - go figure????
# - become: yes
#   become_user: "{{ dns_domain_name_short }}\\{{ user_prefix }}"
#   become_method: runas
#   become_flags: logon_type=new_credentials logon_flags=netcredentials_only
#   vars:
#     ansible_become_password: "{{ windows_password }}"
- block:
  - name: Override ansible user info
  - name: Become student the hackish way
    set_fact:
      ansible_become: true
      ansible_become_user: "{{ dns_domain_name_short }}\\{{ user_prefix }}"
      ansible_become_pass: "{{ windows_password }}"
      ansible_become: yes
      ansible_become_password: "{{  windows_password }}"
      ansible_become_method: runas
  - name: install Chocolatey
@@ -122,6 +132,11 @@
      path: C:\Users\{{ user_prefix }}\AppData\Roaming\Code\User\
      state: directory
  - name: Create VS Code Settings Directory
    win_file:
      path: C:\Users\{{ user_prefix }}\AppData\Roaming\Code\User\
      state: directory
  - name: Configure VS Code Settings File
    win_copy:
      src: files/settings.json
@@ -176,7 +191,7 @@
    win_file:
      path: C:\Users\{{ user_prefix }}\Desktop\EC2 Microsoft Windows Guide.website
      state: absent
  always:
  - name: Restore ansible user info
    set_fact:
      ansible_become: no
@@ -195,11 +210,3 @@
- include_tasks: adv_lab.yml
  when: advanced_lab | d(false) | bool
  # RM: Removes the user from the admin group after Git configuration
- name: Remove Ansible group from local Administrators
  win_group_membership:
    name: Administrators
    members:
    - "{{ dns_domain_name_short }}\\Ansible Users"
    state: absent