chore: rename roles
diff --git a/roles/neutron/README.md b/roles/neutron/README.md
new file mode 100644
index 0000000..252c90a
--- /dev/null
+++ b/roles/neutron/README.md
@@ -0,0 +1 @@
+# `neutron`
diff --git a/roles/neutron/defaults/main.yml b/roles/neutron/defaults/main.yml
new file mode 100644
index 0000000..584d3e9
--- /dev/null
+++ b/roles/neutron/defaults/main.yml
@@ -0,0 +1,26 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+neutron_helm_release_name: neutron
+neutron_helm_chart_path: "{{ role_path }}/../../charts/neutron/"
+neutron_helm_chart_ref: /usr/local/src/neutron
+
+neutron_helm_release_namespace: openstack
+neutron_helm_values: {}
+
+# List of networks to provision inside OpenStack
+neutron_networks: []
+
+# List of annotations to apply to the Ingress
+neutron_ingress_annotations: {}
diff --git a/roles/neutron/meta/main.yml b/roles/neutron/meta/main.yml
new file mode 100644
index 0000000..9c8f17f
--- /dev/null
+++ b/roles/neutron/meta/main.yml
@@ -0,0 +1,35 @@
+# Copyright (c) 2022 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+galaxy_info:
+  author: VEXXHOST, Inc.
+  description: Ansible role for OpenStack Neutron
+  license: Apache-2.0
+  min_ansible_version: 5.5.0
+  standalone: false
+  platforms:
+    - name: Ubuntu
+      versions:
+        - focal
+
+dependencies:
+  - role: defaults
+  - role: openstacksdk
+  - role: openstack_helm_endpoints
+    vars:
+      openstack_helm_endpoints_chart: neutron
+  - role: upload_helm_chart
+    vars:
+      upload_helm_chart_src: "{{ neutron_helm_chart_path }}"
+      upload_helm_chart_dest: "{{ neutron_helm_chart_ref }}"
diff --git a/roles/neutron/tasks/main.yml b/roles/neutron/tasks/main.yml
new file mode 100644
index 0000000..b2a42f0
--- /dev/null
+++ b/roles/neutron/tasks/main.yml
@@ -0,0 +1,105 @@
+# Copyright (c) 2022 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Uninstall the legacy HelmRelease
+  run_once: true
+  block:
+    - name: Suspend the existing HelmRelease
+      kubernetes.core.k8s:
+        state: patched
+        api_version: helm.toolkit.fluxcd.io/v2beta1
+        kind: HelmRelease
+        name: "{{ neutron_helm_release_name }}"
+        namespace: "{{ neutron_helm_release_namespace }}"
+        definition:
+          spec:
+            suspend: true
+
+    - name: Remove the existing HelmRelease
+      kubernetes.core.k8s:
+        state: absent
+        api_version: helm.toolkit.fluxcd.io/v2beta1
+        kind: HelmRelease
+        name: "{{ neutron_helm_release_name }}"
+        namespace: "{{ neutron_helm_release_namespace }}"
+
+- name: Deploy Helm chart
+  run_once: true
+  kubernetes.core.helm:
+    name: "{{ neutron_helm_release_name }}"
+    chart_ref: "{{ neutron_helm_chart_ref }}"
+    release_namespace: "{{ neutron_helm_release_namespace }}"
+    create_namespace: true
+    kubeconfig: /etc/kubernetes/admin.conf
+    values: "{{ _neutron_helm_values | combine(neutron_helm_values, recursive=True) }}"
+
+- name: Create Ingress
+  ansible.builtin.include_role:
+    name: openstack_helm_ingress
+  vars:
+    openstack_helm_ingress_endpoint: network
+    openstack_helm_ingress_service_name: neutron-server
+    openstack_helm_ingress_service_port: 9696
+    openstack_helm_ingress_annotations: "{{ neutron_ingress_annotations }}"
+
+- name: Create networks
+  when: neutron_networks | length > 0
+  block:
+    - name: Wait until network service ready
+      kubernetes.core.k8s_info:
+        api_version: apps/v1
+        kind: Deployment
+        name: neutron-server
+        namespace: openstack
+        wait_sleep: 10
+        wait_timeout: 600
+        wait: true
+        wait_condition:
+          type: Available
+          status: true
+
+    - name: Create networks
+      openstack.cloud.network:
+        cloud: atmosphere
+        # Network settings
+        name: "{{ item.name }}"
+        external: "{{ item.external | default(omit) }}"
+        shared: "{{ item.shared | default(omit) }}"
+        mtu_size: "{{ item.mtu_size | default(omit) }}"
+        port_security_enabled: "{{ item.port_security_enabled | default(omit) }}"
+        provider_network_type: "{{ item.provider_network_type | default(omit) }}"
+        provider_physical_network: "{{ item.provider_physical_network | default(omit) }}"
+        provider_segmentation_id: "{{ item.provider_segmentation_id | default(omit) }}"
+      loop: "{{ neutron_networks }}"
+
+    - name: Create subnets
+      openstack.cloud.subnet:
+        cloud: atmosphere
+        # Subnet settings
+        network_name: "{{ item.0.name }}"
+        name: "{{ item.1.name }}"
+        ip_version: "{{ item.1.ip_version | default(omit) }}"
+        cidr: "{{ item.1.cidr | default(omit) }}"
+        gateway_ip: "{{ item.1.gateway_ip | default(omit) }}"
+        no_gateway_ip: "{{ item.1.no_gateway_ip | default(omit) }}"
+        allocation_pool_start: "{{ item.1.allocation_pool_start | default(omit) }}"
+        allocation_pool_end: "{{ item.1.allocation_pool_end | default(omit) }}"
+        dns_nameservers: "{{ item.1.dns_nameservers | default(omit) }}"
+        enable_dhcp: "{{ item.1.enable_dhcp | default(omit) }}"
+        host_routes: "{{ item.1.host_routes | default(omit) }}"
+        ipv6_address_mode: "{{ item.1.ipv6_address_mode | default(omit) }}"
+        ipv6_ra_mode: "{{ item.1.ipv6_ra_mode | default(omit) }}"
+      with_subelements:
+        - "{{ neutron_networks }}"
+        - subnets
diff --git a/roles/neutron/vars/main.yml b/roles/neutron/vars/main.yml
new file mode 100644
index 0000000..cdab428
--- /dev/null
+++ b/roles/neutron/vars/main.yml
@@ -0,0 +1,66 @@
+# Copyright (c) 2022 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+_neutron_helm_values:
+  endpoints: "{{ openstack_helm_endpoints }}"
+  images:
+    tags: "{{ atmosphere_images | vexxhost.atmosphere.openstack_helm_image_tags('neutron') }}"
+  pod:
+    replicas:
+      server: 3
+  conf:
+    paste:
+      composite:neutronapi_v2_0:
+        keystone: cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
+    neutron:
+      DEFAULT:
+        api_workers: 8
+        dhcp_agents_per_network: 3
+        log_config_append: null
+        rpc_workers: 8
+        service_plugins: qos,router,segments,trunk,vpnaas
+        external_dns_driver: designate
+      cors:
+        allowed_origin: "*"
+      nova:
+        live_migration_events: true
+      oslo_messaging_notifications:
+        driver: noop
+      service_providers:
+        service_provider: VPN:strongswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
+    dhcp_agent:
+      DEFAULT:
+        dnsmasq_dns_servers: "{{ neutron_coredns_cluster_ip | default('10.96.0.20') }}"
+        enable_isolated_metadata: true
+    l3_agent:
+      AGENT:
+        extensions: vpnaas
+      vpnagent:
+        vpn_device_driver: neutron_vpnaas.services.vpn.device_drivers.strongswan_ipsec.StrongSwanDriver
+    metadata_agent:
+      DEFAULT:
+        nova_metadata_port: 8775
+        metadata_proxy_shared_secret: "{{ openstack_helm_endpoints['compute_metadata']['secret'] }}"
+    plugins:
+      ml2_conf:
+        ml2:
+          extension_drivers: dns_domain_ports,port_security,qos
+          type_drivers: flat,gre,vlan,vxlan
+        ml2_type_gre:
+          tunnel_id_ranges: 1:1000
+        ml2_type_vlan:
+          network_vlan_ranges: external:1:4094
+  manifests:
+    ingress_server: false
+    service_ingress_server: false