Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ansible-lint
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mock_modules:
- orka_image_list
- orka_image_push
- orka_image_delete
- network_setup

exclude_paths:
- roles/install_engine/tasks/main.yml
32 changes: 32 additions & 0 deletions .ansible/modules/network_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This is a mocked Ansible module generated by ansible-lint
from ansible.module_utils.basic import AnsibleModule

DOCUMENTATION = '''
module: network_setup

short_description: Mocked
version_added: "1.0.0"
description: Mocked

author:
- ansible-lint (@nobody)
'''
EXAMPLES = '''mocked'''
RETURN = '''mocked'''


def main():
result = dict(
changed=False,
original_message='',
message='')

module = AnsibleModule(
argument_spec=dict(),
supports_check_mode=True,
)
module.exit_json(**result)


if __name__ == "__main__":
main()
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,30 @@ Optional variables:

- `uninstall_engine_data` (default `true`) — remove `/opt/orka` (engine data, state, and logs). Set to `false` to preserve VM state across reinstalls.

#### Configure Hosts for Harbor (MSDC)

When running at MacStadium (MSDC) and using Harbor for OCI image storage, the Mac hosts must be configured to reach Harbor.

The following variables are required:

- `msdc_storage_network`: The first 3 octets of the storage network, e.g. 172.16.180
- `msdc_storage_vlan`: The VLAN tag, e.g. 2870
- `configure_harbor_msdc_region`: The MSDC region, must be one of 'atl', 'las' or 'dub'
- `configure_harbor_msdc_domain`: The domain for Harbor, e.g. my-harbor-01.oci.las1.macstadiumcloud.com
- `configure_harbor_msdc_ip`: The IP address for the Harbor server, e.g. 10.221.189.254

To configure the hosts, run:

```bash
ansible-playbook configure_harbor_msdc.yml -i dev/inventory
```

**NOTE**: To completely remove the Harbor configuration and storage VLAN interface, run:

```bash
ansible-playbook configure_harbor_msdc.yml -i dev/inventory -e "configure_storage_interface_msdc_remove=true" -e "configure_harbor_msdc_remove=true"
```

#### Install Android SDK

To install the Android SDK and AVD runtime tooling on target hosts:
Expand Down
17 changes: 17 additions & 0 deletions configure_harbor_msdc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
- name: Configure access for Harbor on target hosts at MSDC
hosts: hosts
gather_facts: false
module_defaults:
ansible.builtin.setup:
gather_timeout: 20
pre_tasks:
- name: Gather minimal facts
ansible.builtin.setup:
filter:
- "ansible_default_ipv4"
tags:
- always
roles:
- configure_storage_interface_msdc
- configure_harbor_msdc
272 changes: 272 additions & 0 deletions library/network_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

DOCUMENTATION = r"""
module: network_setup
short_description: Sets up a VLAN
description:
- Configure a VLAN and network service
options:
name:
description:
- VLAN name
type: string
required: true
device:
description:
- The device used (en0, en1, etc...)
type: string
required: false
tag:
description:
- The VLAN tag
type: string
required: false
ip:
description:
- IP of the service
type: str
required: false
mask:
description:
- Mask of the service
type: str
required: false
router:
description:
- Router of the service
type: str
required: false
state:
description:
- Add, delete, enable or disable the interface
type: str
choices: [ present, absent, enable, disable ]
default: present
force:
description:
- Apply the change regardless of current state
type: bool
default: false
author:
- Ivan Spasov (@ispasov)
- Spike Burton (@spikeburton)
"""

EXAMPLES = r"""
- name: Add a storage vlan
network_setup:
name: storage
device: en0
tag: 2339
ip: 10.172.1.12
mask: 255.255.254.0
router: 10.172.1.11
- name: Remove a storage vlan
network_setup:
name: storage
device: en0
tag: 2339
ip: 10.172.1.12
mask: 255.255.254.0
router: 10.172.1.11
state: absent
- name: Force recreate a storage vlan
network_setup:
name: storage
device: en0
tag: 2339
ip: 10.172.1.12
mask: 255.255.254.0
router: 10.172.1.11
force: true
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text


class NetworkServiceModuleError(Exception):
pass


class NetworkService(object):
def __init__(self, module):
self.module = module
self.name = module.params["name"]
self.device = module.params["device"]
self.tag = module.params["tag"]
self.ip = module.params["ip"]
self.mask = module.params["mask"]
self.router = module.params["router"]
self.state = module.params["state"]
self.force = module.params["force"]

def execute_command(self, cmd):
cmd = [to_text(item) for item in cmd]
(rc, out, err) = self.module.run_command(cmd)
if rc != 0:
raise NetworkServiceModuleError(out + err)

return out

def vlan_exists(self):
out = self.execute_command(["networksetup", "-listVlans"])

return f"VLAN User Defined Name: {self.name}" in out.splitlines()

def create(self):
self.create_vlan()
self.configure_service()
self.configure_dns()

def create_vlan(self):
cmd = ["networksetup", "-createVLAN", self.name, self.device, self.tag]
self.execute_command(cmd)

def configure_service(self):
# An empty router leaves the service without a default gateway. Directly
# connected subnets (e.g. the MSDC storage VLAN) don't need one, and
# omitting it avoids ever competing for the host's default route.
cmd = [
"networksetup",
"-setmanual",
f"{self.name} Configuration",
self.ip,
self.mask,
self.router or "",
]
self.execute_command(cmd)

def configure_dns(self):
cmd = [
"networksetup",
"-setdnsservers",
f"{self.name} Configuration",
"8.8.8.8",
"1.1.1.1",
]
self.execute_command(cmd)

def vlan_changed(self):
out = self.execute_command(["networksetup", "-listVlans"])
vlan_lines = out.splitlines()
vlan_name_index = vlan_lines.index(f"VLAN User Defined Name: {self.name}")
vlan_device = (
vlan_lines[vlan_name_index + 1].replace("Parent Device:", "").strip()
)
vlan_tag = vlan_lines[vlan_name_index + 3].replace("Tag:", "").strip()

return vlan_device != self.device or vlan_tag != self.tag

def service_changed(self):
out = self.execute_command(
["networksetup", "-getinfo", f"{self.name} Configuration"]
)
service_lines = out.splitlines()
service_ip = service_lines[1].replace("IP address:", "").strip()
service_mask = service_lines[2].replace("Subnet mask:", "").strip()
service_router = service_lines[3].replace("Router:", "").strip()

return (
service_ip != self.ip
or service_mask != self.mask
or service_router != (self.router or "")
)

def needs_update(self):
return self.vlan_changed() or self.service_changed()

def delete(self):
cmd = ["networksetup", "-deleteVLAN", self.name, self.device, self.tag]
self.execute_command(cmd)

def service_exists(self):
cmd = ["networksetup", "-listallnetworkservices"]
out = self.execute_command(cmd)

for line in out.splitlines():
service_name = line.lstrip("*").strip()
if service_name == self.name:
return True
return False

def service_enabled(self):
cmd = ["networksetup", "-getnetworkserviceenabled", self.name]
out = self.execute_command(cmd)
return out.strip().lower() == "enabled"

def enable_service(self):
cmd = ["networksetup", "-setnetworkserviceenabled", self.name, "on"]
self.execute_command(cmd)

def disable_service(self):
cmd = ["networksetup", "-setnetworkserviceenabled", self.name, "off"]
self.execute_command(cmd)

def set_service_state(self):
should_enable = self.state == "enable"
is_currently_enabled = self.service_enabled()

if self.force or is_currently_enabled != should_enable:
self.enable_service() if should_enable else self.disable_service()
return True

return False

def run(self):
changed = False

if self.state == "present":
if not self.vlan_exists():
self.create()
changed = True
elif self.force or self.needs_update():
self.delete()
self.create()
changed = True

elif self.state == "absent" and self.vlan_exists():
self.delete()
changed = True

elif self.service_exists() and self.state in ["enable", "disable"]:
changed = self.set_service_state()

return changed


def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type="str", required=True),
device=dict(type="str"),
tag=dict(type="str"),
ip=dict(type="str"),
mask=dict(type="str", default="manual"),
router=dict(type="str"),
state=dict(
type="str",
default="present",
choices=["present", "absent", "enable", "disable"],
),
force=dict(type="bool", default=False),
),
required_if=[
("state", "present", ("device", "tag", "ip", "mask")),
("state", "absent", ("device", "tag")),
],
supports_check_mode=False,
)

network_service = NetworkService(module)
try:
changed = network_service.run()
except Exception as e:
module.fail_json(msg=str(e))

module.exit_json(changed=changed)


if __name__ == "__main__":
main()
8 changes: 8 additions & 0 deletions roles/configure_harbor_msdc/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# msdc_storage_network:
# configure_harbor_msdc_region: # Should be one of 'atl', 'las' or 'dub'
# configure_harbor_msdc_domain:
# configure_harbor_msdc_ip:
configure_harbor_msdc_s3_domain: 1.obj.{{ configure_harbor_msdc_region }}1.macstadiumcloud.com
configure_harbor_msdc_s3_ip: "{{ msdc_storage_network }}.1"
configure_harbor_msdc_remove: false
18 changes: 18 additions & 0 deletions roles/configure_harbor_msdc/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
- name: Add entries to /etc/hosts
become: true
ansible.builtin.blockinfile:
path: /etc/hosts
marker: "{{ configure_harbor_msdc_marker }}"
block: |
{{ configure_harbor_msdc_ip }} {{ configure_harbor_msdc_domain }}
{{ configure_harbor_msdc_s3_ip }} {{ configure_harbor_msdc_s3_domain }}
when: not configure_harbor_msdc_remove | bool

- name: Remove entries from /etc/hosts
become: true
ansible.builtin.blockinfile:
path: /etc/hosts
marker: "{{ configure_harbor_msdc_marker }}"
state: absent
when: configure_harbor_msdc_remove | bool
2 changes: 2 additions & 0 deletions roles/configure_harbor_msdc/vars/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
configure_harbor_msdc_marker: "# {mark} Harbor FQDNs"
Loading
Loading