diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 00839baf40..2db6631b79 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -162,6 +162,8 @@ rabbitmq_management_port: "15672"
rabbitmq_cluster_port: "25672"
rabbitmq_epmd_port: "4369"
+rdp_port: "8001"
+
outward_rabbitmq_port: "5674"
outward_rabbitmq_management_port: "15674"
outward_rabbitmq_cluster_port: "25674"
@@ -347,6 +349,7 @@ enable_horizon_solum: "{{ enable_solum | bool }}"
enable_horizon_tacker: "{{ enable_tacker | bool }}"
enable_horizon_trove: "{{ enable_trove | bool }}"
enable_horizon_watcher: "{{ enable_watcher | bool }}"
+enable_hyperv: "no"
enable_influxdb: "no"
enable_ironic: "no"
enable_iscsid: "{{ enable_cinder_backend_iscsi | bool or enable_cinder_backend_lvm | bool or enable_ironic | bool }}"
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index e67c7fcefc..69660ddffe 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -60,6 +60,16 @@ control
[haproxy:children]
network
+[hyperv]
+#hyperv_host
+
+[hyperv:vars]
+#ansible_user=user
+#ansible_password=password
+#ansible_port=5986
+#ansible_connection=winrm
+#ansible_winrm_server_cert_validation=ignore
+
[mariadb:children]
control
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index c09d45dd38..8cd706567f 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -81,6 +81,16 @@ control
[haproxy:children]
network
+[hyperv]
+#hyperv_host
+
+[hyperv:vars]
+#ansible_user=user
+#ansible_password=password
+#ansible_port=5986
+#ansible_connection=winrm
+#ansible_winrm_server_cert_validation=ignore
+
[mariadb:children]
control
diff --git a/ansible/roles/neutron/templates/ml2_conf.ini.j2 b/ansible/roles/neutron/templates/ml2_conf.ini.j2
index b18e822a6e..ba7647deec 100644
--- a/ansible/roles/neutron/templates/ml2_conf.ini.j2
+++ b/ansible/roles/neutron/templates/ml2_conf.ini.j2
@@ -3,6 +3,9 @@
{% if enable_ironic | bool %}
tenant_network_types = vxlan, flat
mechanism_drivers = openvswitch
+{% elif enable_hyperv | bool %}
+type_drivers = flat,vlan,vxlan
+tenant_network_types = flat,vlan
{% else %}
# Changing type_drivers after bootstrap can lead to database inconsistencies
type_drivers = flat,vlan,vxlan
@@ -10,13 +13,19 @@ tenant_network_types = vxlan
{% endif %}
{% if neutron_plugin_agent == "openvswitch" %}
+{% if enable_hyperv | bool %}
+mechanism_drivers = openvswitch,hyperv
+{% else %}
mechanism_drivers = openvswitch,l2population
+{% endif %}
{% elif neutron_plugin_agent == "linuxbridge" %}
mechanism_drivers = linuxbridge,l2population
{% endif %}
{% if neutron_extension_drivers %}
extension_drivers = {{ neutron_extension_drivers|map(attribute='name')|join(',') }}
+{% elif enable_hyperv | bool %}
+extension_drivers = port_security
{% endif %}
[ml2_type_vlan]
@@ -33,9 +42,11 @@ flat_networks = *
flat_networks = {% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}{% if not loop.last %},{% endif %}{% endfor %}
{% endif %}
+{% if not enable_hyperv | bool %}
[ml2_type_vxlan]
vni_ranges = 1:1000
vxlan_group = 239.1.1.1
+{% endif %}
[securitygroup]
{% if neutron_plugin_agent == "openvswitch" %}
@@ -45,10 +56,12 @@ firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
{% endif %}
{% if neutron_plugin_agent == "openvswitch" %}
+{% if not enable_hyperv | bool %}
[agent]
tunnel_types = vxlan
l2_population = true
arp_responder = true
+{% endif %}
{% if enable_neutron_dvr | bool %}
enable_distributed_routing = True
@@ -71,7 +84,9 @@ integration_bridge = br-int-{{ item }}
[linux_bridge]
physical_interface_mappings = physnet1:{{ neutron_external_interface }}
+{% if not enable_hyperv | bool %}
[vxlan]
l2_population = true
{% endif %}
+{% endif %}
local_ip = {{ tunnel_interface_address }}
diff --git a/ansible/roles/nova-hyperv/defaults/main.yml b/ansible/roles/nova-hyperv/defaults/main.yml
new file mode 100644
index 0000000000..0b1f9f923b
--- /dev/null
+++ b/ansible/roles/nova-hyperv/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+placement_keystone_user: "placement"
+msi_dir: "%SYSTEMDRIVE%\\OpenStack\\MSIs"
+log_dir: "%SYSTEMDRIVE%\\OpenStack\\Log"
+freerdp_msi_url: "https://cloudbase.it/downloads/FreeRDPWebConnect.msi"
+hyperv_compute_msi: "HyperVNovaCompute.msi"
+freerdp_webconnect_msi: "FreeRDPWebConnect.msi"
diff --git a/ansible/roles/nova-hyperv/handlers/main.yml b/ansible/roles/nova-hyperv/handlers/main.yml
new file mode 100644
index 0000000000..f6cd425d46
--- /dev/null
+++ b/ansible/roles/nova-hyperv/handlers/main.yml
@@ -0,0 +1,15 @@
+---
+- name: Restart nova-compute
+ win_service:
+ name: nova-compute
+ state: restarted
+
+- name: Restart neutron-hyperv-agent
+ win_service:
+ name: neutron-hyperv-agent
+ state: restarted
+
+- name: Restart FreeRDP-WebConnect
+ win_service:
+ name: wsgate
+ state: restarted
diff --git a/ansible/roles/nova-hyperv/tasks/check.yml b/ansible/roles/nova-hyperv/tasks/check.yml
new file mode 100644
index 0000000000..ed97d539c0
--- /dev/null
+++ b/ansible/roles/nova-hyperv/tasks/check.yml
@@ -0,0 +1 @@
+---
diff --git a/ansible/roles/nova-hyperv/tasks/config.yml b/ansible/roles/nova-hyperv/tasks/config.yml
new file mode 100644
index 0000000000..0893e6f50a
--- /dev/null
+++ b/ansible/roles/nova-hyperv/tasks/config.yml
@@ -0,0 +1,35 @@
+---
+- name: Create log directory
+ win_command: "cmd /c mkdir {{ log_dir }}"
+ args:
+ creates: "{{ log_dir }}"
+
+- name: Configure nova-compute
+ win_template:
+ src: "{{ item }}"
+ dest: "%PROGRAMFILES%\\Cloudbase Solutions\\OpenStack\\Nova\\etc\\nova.conf"
+ with_first_found:
+ - "{{ node_custom_config }}/nova-hyperv/{{ inventory_hostname }}/nova_hyperv.conf"
+ - "{{ node_custom_config }}/nova-hyperv/nova_hyperv.conf"
+ - "nova_hyperv.conf.j2"
+ notify: Restart nova-compute
+
+- name: Configure neutron-hyperv-agent
+ win_template:
+ src: "{{ item }}"
+ dest: "%PROGRAMFILES%\\Cloudbase Solutions\\OpenStack\\Nova\\etc\\neutron_hyperv_agent.conf"
+ with_first_found:
+ - "{{ node_custom_config }}/nova-hyperv/{{ inventory_hostname }}/neutron_hyperv_agent.conf"
+ - "{{ node_custom_config }}/nova-hyperv/neutron_hyperv_agent.conf"
+ - "neutron_hyperv_agent.conf.j2"
+ notify: Restart neutron-hyperv-agent
+
+- name: Configure FreeRDP-WebConnect
+ win_template:
+ src: "{{ item }}"
+ dest: "%PROGRAMFILES%\\Cloudbase Solutions\\FreeRDP-WebConnect\\etc\\wsgate.ini"
+ with_first_found:
+ - "{{ node_custom_config }}/nova-hyperv/{{ inventory_hostname }}/wsgate.ini"
+ - "{{ node_custom_config }}/nova-hyperv/wsgate.ini"
+ - "wsgate.ini.j2"
+ notify: Restart FreeRDP-WebConnect
diff --git a/ansible/roles/nova-hyperv/tasks/deploy.yml b/ansible/roles/nova-hyperv/tasks/deploy.yml
new file mode 100644
index 0000000000..77b95e96b3
--- /dev/null
+++ b/ansible/roles/nova-hyperv/tasks/deploy.yml
@@ -0,0 +1,6 @@
+---
+- include: install.yml
+ when: inventory_hostname in groups['hyperv']
+
+- include: config.yml
+ when: inventory_hostname in groups['hyperv']
diff --git a/ansible/roles/nova-hyperv/tasks/install.yml b/ansible/roles/nova-hyperv/tasks/install.yml
new file mode 100644
index 0000000000..c875c94015
--- /dev/null
+++ b/ansible/roles/nova-hyperv/tasks/install.yml
@@ -0,0 +1,26 @@
+---
+- name: Create MSIs download directory
+ win_command: "cmd /c mkdir {{ msi_dir }}"
+ args:
+ creates: "{{ msi_dir }}"
+
+- name: Download Nova and FreeRDP-WebConnect MSIs
+ win_get_url:
+ url: "{{ item.name }}"
+ dest: "{{ item.destination }}"
+ force: no
+ with_items:
+ - { name: "{{ nova_msi_url }}", destination: "{{ msi_dir }}\\{{ hyperv_compute_msi }}" }
+ - { name: "{{ freerdp_msi_url }}", destination: "{{ msi_dir }}\\{{ freerdp_webconnect_msi }}" }
+
+- name: Install the Compute MSI
+ win_command: "msiexec /i {{ hyperv_compute_msi }} SKIPNOVACONF=0"
+ args:
+ chdir: "{{ msi_dir }}"
+ creates: "%PROGRAMFILES%\\Cloudbase Solutions\\OpenStack\\Nova\\bin"
+
+- name: Install the FreeRDP-WebConnect MSI
+ win_command: "msiexec.exe /i {{ freerdp_webconnect_msi }}"
+ args:
+ chdir: "{{ msi_dir }}"
+ creates: "%PROGRAMFILES%\\Cloudbase Solutions\\FreeRDP-WebConnect\\Binaries"
diff --git a/ansible/roles/nova-hyperv/tasks/main.yml b/ansible/roles/nova-hyperv/tasks/main.yml
new file mode 100644
index 0000000000..b017e8b4ad
--- /dev/null
+++ b/ansible/roles/nova-hyperv/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+- include: "{{ action }}.yml"
diff --git a/ansible/roles/nova-hyperv/tasks/reconfigure.yml b/ansible/roles/nova-hyperv/tasks/reconfigure.yml
new file mode 100644
index 0000000000..56169f9727
--- /dev/null
+++ b/ansible/roles/nova-hyperv/tasks/reconfigure.yml
@@ -0,0 +1,2 @@
+---
+- include: "deploy.yml"
diff --git a/ansible/roles/nova-hyperv/templates/neutron_hyperv_agent.conf.j2 b/ansible/roles/nova-hyperv/templates/neutron_hyperv_agent.conf.j2
new file mode 100644
index 0000000000..218c8fe307
--- /dev/null
+++ b/ansible/roles/nova-hyperv/templates/neutron_hyperv_agent.conf.j2
@@ -0,0 +1,18 @@
+[DEFAULT]
+debug = {{ openstack_logging_debug }}
+control_exchange = neutron
+rpc_backend = rabbit
+log_dir = C:\OpenStack\Log
+log_file = neutron-hyperv-agent.log
+transport_url = rabbit://{% for host in groups['rabbitmq'] %}{{ rabbitmq_user }}:{{ rabbitmq_password }}@{{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ rabbitmq_port }}{% if not loop.last %},{% endif %}{% endfor %}
+
+
+[AGENT]
+polling_interval = 2
+physical_network_vswitch_mappings = *:{{ vswitch_name }}
+enable_metrics_collection = false
+enable_qos_extension = false
+
+[SECURITYGROUP]
+firewall_driver = hyperv
+enable_security_group = true
diff --git a/ansible/roles/nova-hyperv/templates/nova_hyperv.conf.j2 b/ansible/roles/nova-hyperv/templates/nova_hyperv.conf.j2
new file mode 100644
index 0000000000..fbdf92857b
--- /dev/null
+++ b/ansible/roles/nova-hyperv/templates/nova_hyperv.conf.j2
@@ -0,0 +1,61 @@
+[DEFAULT]
+compute_driver = compute_hyperv.driver.HyperVDriver
+instances_path = C:\OpenStack\Instances
+use_cow_images = true
+flat_injected = true
+mkisofs_cmd = C:\Program Files\Cloudbase Solutions\OpenStack\Nova\bin\mkisofs.exe
+debug = {{ openstack_logging_debug }}
+allow_resize_to_same_host = true
+running_deleted_instance_action = reap
+running_deleted_instance_poll_interval = 120
+resize_confirm_window = 5
+resume_guests_state_on_host_boot = true
+rpc_response_timeout = 1800
+lock_path = C:\OpenStack\Log
+vif_plugging_is_fatal = false
+vif_plugging_timeout = 60
+rpc_backend = rabbit
+log_dir = C:\OpenStack\Log
+log_file = nova-compute.log
+force_config_drive = True
+transport_url = rabbit://{% for host in groups['rabbitmq'] %}{{ rabbitmq_user }}:{{ rabbitmq_password }}@{{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ rabbitmq_port }}{% if not loop.last %},{% endif %}{% endfor %}
+
+
+[placement]
+auth_type = password
+auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}/v3
+project_name = service
+username = {{ placement_keystone_user }}
+password = {{ placement_keystone_password }}
+project_domain_name = default
+user_domain_name = default
+os_region_name = {{ openstack_region_name }}
+
+[glance]
+api_servers = {{ internal_protocol }}://{% for host in groups['glance-api'] %}{{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ glance_api_port }}{% if not loop.last %},{% endif %}{% endfor %}
+
+
+[hyperv]
+vswitch_name = {{ vswitch_name }}
+limit_cpu_features = false
+config_drive_inject_password = true
+qemu_img_cmd = C:\Program Files\Cloudbase Solutions\OpenStack\Nova\bin\qemu-img.exe
+config_drive_cdrom = true
+dynamic_memory_ratio = 1
+enable_instance_metrics_collection = false
+
+
+[rdp]
+enabled = true
+html5_proxy_base_url = {{ public_protocol }}://{{ ansible_fqdn }}:{{ rdp_port }}
+
+[neutron]
+url = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ neutron_server_port }}
+auth_strategy = keystone
+project_domain_name = default
+project_name = service
+user_domain_name = default
+username = {{ neutron_keystone_user }}
+password = {{ neutron_keystone_password }}
+auth_url = {{ keystone_admin_url }}/v3
+auth_plugin = v3password
diff --git a/ansible/roles/nova-hyperv/templates/wsgate.ini.j2 b/ansible/roles/nova-hyperv/templates/wsgate.ini.j2
new file mode 100644
index 0000000000..e11c8d37dd
--- /dev/null
+++ b/ansible/roles/nova-hyperv/templates/wsgate.ini.j2
@@ -0,0 +1,28 @@
+[global]
+debug = {{ openstack_logging_debug }}
+redirect = false
+port = {{ rdp_port }}
+bindaddr = {% for host in groups['hyperv'] %}{% for ip in hostvars[inventory_hostname]['ansible_ip_addresses'] %}{% if host == ip %}{{ ip }}{% endif %}{% endfor %}{% endfor %}
+
+
+[http]
+documentroot = C:\Program Files\Cloudbase Solutions\FreeRDP-WebConnect\WebRoot\
+
+[ssl]
+port=4430
+bindaddr = {% for host in groups['hyperv'] %}{% for ip in hostvars[inventory_hostname]['ansible_ip_addresses'] %}{% if host == ip %}{{ ip }}{% endif %}{% endfor %}{% endfor %}
+
+certfile = C:\Program Files\Cloudbase Solutions\FreeRDP-WebConnect\etc\server.cer
+
+[rdpoverride]
+nofullwindowdrag = true
+
+[openstack]
+authurl = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}/v2.0
+tenantname = service
+username = {{ nova_keystone_user }}
+password = {{ nova_keystone_password }}
+
+[hyperv]
+hostusername = {{ hyperv_username }}
+hostpassword = {{ hyperv_password }}
diff --git a/ansible/site.yml b/ansible/site.yml
index acbc212714..064ba11e3c 100644
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -307,6 +307,16 @@
tags: openvswitch,
when: enable_openvswitch | bool }
+- name: Apply nova-hyperv role
+ gather_facts: false
+ hosts:
+ - hyperv
+ serial: '{{ serial|default("0") }}'
+ roles:
+ - { role: nova-hyperv,
+ tags: nova-hyperv,
+ when: enable_hyperv | bool }
+
# (gmmaha): Please do not change the order listed here. The current order is a
# workaround to fix the bug https://bugs.launchpad.net/kolla/+bug/1546789
- name: Apply role neutron
diff --git a/doc/hyperv-guide.rst b/doc/hyperv-guide.rst
new file mode 100644
index 0000000000..8ff966c54c
--- /dev/null
+++ b/doc/hyperv-guide.rst
@@ -0,0 +1,163 @@
+.. _hyperv-guide:
+
+====================
+Nova-HyperV in Kolla
+====================
+
+Overview
+========
+Currently, Kolla can deploy the following OpenStack services for Hyper-V:
+
+* nova-compute
+* neutron-hyperv-agent
+* wsgate
+
+It is possible to use Hyper-V as a compute node within an OpenStack Deployment.
+The nova-compute service runs as openstack-compute, a 64-bit service directly
+upon the Windows platform with the Hyper-V role enabled. The necessary Python
+components as well as the nova-compute service are installed directly onto
+the Windows platform. Windows Clustering Services are not needed for
+functionality within the OpenStack infrastructure.
+
+The wsgate is the FreeRDP-WebConnect service that is used for accessing
+virtual machines from Horizon web interface.
+
+.. note::
+
+ HyperV services are not currently deployed as containers. This functionality
+ is in development. The current implementation installs OpenStack services
+ via MSIs.
+
+
+.. note::
+
+ HyperV services do not currently support outside the box upgrades. Manual
+ upgrades are required for this process. MSI release versions can be found
+ `here
+ `__.
+ To upgrade an existing MSI to a newer version, simply uninstall the current
+ MSI and install the newer one. This will not delete the configuration files.
+ To preserve the configuration files, check the Skip configuration checkbox
+ during installation.
+
+
+Preparation for Hyper-V node
+============================
+
+Ansible communicates with Hyper-V host via WinRM protocol. An HTTPS WinRM
+listener needs to be configured on the Hyper-V host, which can be easily
+created with
+`this PowerShell script
+`__.
+
+
+A virtual switch has to be created with which Hyper-V virtual machines
+communicate with OpenStack. To quickly enable an interface to be used as a
+Virtual Interface the following PowerShell may be used:
+
+.. code-block:: console
+
+ PS C:\> $if = Get-NetIPAddress -IPAddress 192* | Get-NetIPInterface
+ PS C:\> New-VMSwitch -NetAdapterName $if.ifAlias -Name YOUR_BRIDGE_NAME -AllowManagementOS $false
+
+.. note::
+
+ It is very important to make sure that when you are using a Hyper-V node with only 1 NIC the
+ -AllowManagementOS option is set on True, otherwise you will lose connectivity to the Hyper-V node.
+
+
+To prepare the Hyper-V node to be able to attach to volumes provided by cinder you must
+first make sure the Windows iSCSI initiator service is running and started automatically.
+
+.. code-block:: console
+
+ PS C:\> Set-Service -Name MSiSCSI -StartupType Automatic
+ PS C:\> Start-Service MSiSCSI
+
+
+
+Preparation for Kolla deployer node
+===================================
+
+Hyper-V role is required, enable it in ``/etc/kolla/globals.yml``:
+
+.. code-block:: console
+
+ enable_hyperv: "yes"
+
+Hyper-V options are also required in ``/etc/kolla/globals.yml``:
+
+.. code-block:: console
+
+ hyperv_username:
+ hyperv_password:
+ vswitch_name:
+ nova_msi_url: "https://www.cloudbase.it/downloads/HyperVNovaCompute_Beta.msi"
+
+The virtual switch is the same one created on the HyperV setup part.
+For nova_msi_url, different Nova MSI (Mitaka/Newton/Ocata) versions can be found on
+`Cloudbase website
+`__.
+
+
+Add the Hyper-V node in ``ansible/inventory`` file:
+
+.. code-block:: console
+
+ [hyperv]
+
+
+ [hyperv:vars]
+ ansible_user=
+ ansible_password=
+ ansible_port=5986
+ ansible_connection=winrm
+ ansible_winrm_server_cert_validation=ignore
+
+pywinrm package needs to be installed in order for Ansible to work on the HyperV node:
+
+.. code-block:: console
+
+ pip install "pywinrm>=0.2.2"
+
+.. note::
+
+ In case of a test deployment with controller and compute nodes as virtual machines
+ on Hyper-V, if VLAN tenant networking is used, trunk mode has to be enabled on the
+ VMs:
+
+.. code-block:: console
+
+ Set-VMNetworkAdapterVlan -Trunk -AllowedVlanIdList -NativeVlanId 0
+
+networking-hyperv mechanism driver is needed for neutron-server to communicate with
+HyperV nova-compute. This can be built with source images by default. Manually it
+can be intalled in neutron-server container with pip:
+
+.. code-block:: console
+
+ pip install "networking-hyperv>=4.0.0"
+
+For neutron_extension_drivers, ``port_security`` and ``qos`` are currently supported by the networking-hyperv
+mechanism driver. By default only ``port_security`` is set.
+
+
+Verify Operations
+=================
+
+OpenStack HyperV services can be inspected and managed from PowerShell:
+
+.. code-block:: console
+
+ PS C:\> Get-Service nova-compute
+ PS C:\> Get-Service neutron-hyperv-agent
+
+.. code-block:: console
+
+ PS C:\> Restart-Service nova-compute
+ PS C:\> Restart-Service neutron-hyperv-agent
+
+
+For more information on OpenStack HyperV, see
+`Hyper-V virtualization platform
+`__.
diff --git a/doc/index.rst b/doc/index.rst
index 44c1a11b92..d20f056695 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -63,6 +63,7 @@ Services
cinder-guide
cinder-guide-hnas
designate-guide
+ hyperv-guide
ironic-guide
manila-guide
manila-hnas-guide
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index e343886939..0e71b350c8 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -158,6 +158,7 @@ kolla_internal_vip_address: "10.10.10.254"
#enable_horizon_tacker: "{{ enable_tacker | bool }}"
#enable_horizon_trove: "{{ enable_trove | bool }}"
#enable_horizon_watcher: "{{ enable_watcher | bool }}"
+#enable_hyperv: "no"
#enable_influxdb: "no"
#enable_ironic: "no"
#enable_karbor: "no"
@@ -302,6 +303,15 @@ designate_ns_record: "sample.openstack.org"
#########################
#nova_backend_ceph: "{{ enable_ceph }}"
+###################
+# Hyper-V options
+###################
+# Hyper-V can be used as hypervisor
+#hyperv_username: "user"
+#hyperv_password: "password"
+#vswitch_name: "vswitch"
+# URL from which Nova Hyper-V MSI is downloaded
+#nova_msi_url: "https://www.cloudbase.it/downloads/HyperVNovaCompute_Beta.msi"
##############################
# Horizon - Dashboard Options
diff --git a/releasenotes/notes/hyperv-ansible-role-dd6062f36470e7b6.yaml b/releasenotes/notes/hyperv-ansible-role-dd6062f36470e7b6.yaml
new file mode 100644
index 0000000000..dbaf470db2
--- /dev/null
+++ b/releasenotes/notes/hyperv-ansible-role-dd6062f36470e7b6.yaml
@@ -0,0 +1,3 @@
+---
+features:
+ - Implement Nova-HyperV ansible role