Simone Tiraboschi has uploaded a new change for review. Change subject: WIP: packaging: setup: let the user configure engine VM networking ......................................................................
WIP: packaging: setup: let the user configure engine VM networking Let the user specify a static configuration for the engine VM network configuration. The configuration will be applyed via cloud-init. Change-Id: Ic09f4d92e44f1bf810f06ada703e533b8c5e2061 Bug-Url: https://bugzilla.redhat.com/1223801 Signed-off-by: Simone Tiraboschi <stira...@redhat.com> --- M ovirt-hosted-engine-setup.spec.in M src/ovirt_hosted_engine_setup/constants.py M src/plugins/ovirt-hosted-engine-setup/network/gateway.py M src/plugins/ovirt-hosted-engine-setup/vm/cloud_init.py 4 files changed, 187 insertions(+), 3 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-hosted-engine-setup refs/changes/57/41357/1 diff --git a/ovirt-hosted-engine-setup.spec.in b/ovirt-hosted-engine-setup.spec.in index 318757a..9e6c78e 100644 --- a/ovirt-hosted-engine-setup.spec.in +++ b/ovirt-hosted-engine-setup.spec.in @@ -46,6 +46,7 @@ Requires: python Requires: python-ethtool >= 0.6-3 Requires: python-paramiko +Requires: python-netaddr Requires: sanlock >= 2.8 Requires: sanlock-python >= 2.8 Requires: sudo diff --git a/src/ovirt_hosted_engine_setup/constants.py b/src/ovirt_hosted_engine_setup/constants.py index c6195d6..f4a775b 100644 --- a/src/ovirt_hosted_engine_setup/constants.py +++ b/src/ovirt_hosted_engine_setup/constants.py @@ -721,6 +721,24 @@ @ohostedattrs( answerfile=True, ) + def CLOUD_INIT_VM_STATIC_CIDR(self): + return 'OVEHOSTED_VM/cloudinitVMStaticCIDR' + + @ohostedattrs( + answerfile=True, + ) + def CLOUD_INIT_VM_DNS1(self): + return 'OVEHOSTED_VM/cloudinitVMDNS1' + + @ohostedattrs( + answerfile=True, + ) + def CLOUD_INIT_VM_DNS2(self): + return 'OVEHOSTED_VM/cloudinitVMDNS2' + + @ohostedattrs( + answerfile=True, + ) def CDROM_UUID(self): return 'OVEHOSTED_VM/cdromUUID' @@ -853,6 +871,7 @@ CONFIG_STORAGE_LATE = 'ohosted.storage.configuration.late' CONFIG_STORAGE_BLOCKD = 'ohosted.storage.blockd.configuration.available' CONFIG_STORAGE_NFS = 'ohosted.storage.nfs.configuration.available' + CONFIG_GATEWAY = 'ohosted.networking.gateway.configuration.available' GLUSTER_PROVISIONING = 'ohosted.storage.gluster.provisioned' CONFIG_ADDITIONAL_HOST = 'ohosted.core.additional.host' CONFIG_CLOUD_INIT_OPTIONS = 'ohosted.boot.configuration.cloud_init_options' diff --git a/src/plugins/ovirt-hosted-engine-setup/network/gateway.py b/src/plugins/ovirt-hosted-engine-setup/network/gateway.py index e687d72..25024f4 100644 --- a/src/plugins/ovirt-hosted-engine-setup/network/gateway.py +++ b/src/plugins/ovirt-hosted-engine-setup/network/gateway.py @@ -106,6 +106,7 @@ before=( ohostedcons.Stages.DIALOG_TITLES_E_NETWORK, ), + name=ohostedcons.Stages.CONFIG_GATEWAY, ) def _customization(self): diff --git a/src/plugins/ovirt-hosted-engine-setup/vm/cloud_init.py b/src/plugins/ovirt-hosted-engine-setup/vm/cloud_init.py index 8f84468..2170c78 100644 --- a/src/plugins/ovirt-hosted-engine-setup/vm/cloud_init.py +++ b/src/plugins/ovirt-hosted-engine-setup/vm/cloud_init.py @@ -29,6 +29,8 @@ import shutil import tempfile +import netaddr + from otopi import constants as otopicons from otopi import plugin from otopi import util @@ -52,6 +54,30 @@ self._enable = False self._directory_name = None + def _validate_ip_cidr(self, ipcidr): + try: + ip = netaddr.IPNetwork(ipcidr) + if not ( + ip.ip and + ip.ip.is_unicast() and + not ip.ip.is_loopback() + ): + return None + if len(list(ip)) > 1: + if not ( + ip.network and + ip.ip != ip.network and + ip.broadcast and + ip.ip != ip.broadcast + ): + return None + except netaddr.AddrFormatError: + return None + return ip + + def _validate_ip(self, ip): + return self._validate_ip_cidr(ip + '/32') + @plugin.event( stage=plugin.Stages.STAGE_INIT, ) @@ -69,6 +95,10 @@ ) self.environment.setdefault( ohostedcons.VMEnv.CLOUD_INIT_INSTANCE_HOSTNAME, + None + ) + self.environment.setdefault( + ohostedcons.VMEnv.CLOUD_INIT_EXECUTE_ESETUP, None ) self.environment.setdefault( @@ -109,6 +139,9 @@ self.environment[ohostedcons.VMEnv.CLOUD_INIT_ROOTPWD], self.environment[ohostedcons.VMEnv.CLOUD_INIT_INSTANCE_HOSTNAME], self.environment[ohostedcons.VMEnv.CLOUD_INIT_EXECUTE_ESETUP], + self.environment[ohostedcons.VMEnv.CLOUD_INIT_VM_STATIC_CIDR], + self.environment[ohostedcons.VMEnv.CLOUD_INIT_VM_DNS1], + self.environment[ohostedcons.VMEnv.CLOUD_INIT_VM_DNS1], ]) == set([None]) if interactive: @@ -208,6 +241,8 @@ ohostedcons.VMEnv.CLOUD_INIT_ROOTPWD ] = False + self._configure_vm_networking() + self.environment[ ohostedcons.VMEnv.CLOUD_INIT_EXECUTE_ESETUP ] = self.dialog.queryString( @@ -252,12 +287,116 @@ ] or self.environment[ ohostedcons.VMEnv.CLOUD_INIT_EXECUTE_ESETUP + ] or + self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_STATIC_CIDR + ] or + self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_DNS1 + ] or + self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_DNS2 ] ): self.environment[ ohostedcons.VMEnv.GENERATE_CLOUD_INIT_ISO ] = ohostedcons.Const.CLOUD_INIT_GENERATE self._enable = True + + @plugin.event( + stage=plugin.Stages.STAGE_CUSTOMIZATION, + after=( + ohostedcons.Stages.DIALOG_TITLES_S_NETWORK, + ohostedcons.Stages.CONFIG_GATEWAY, + ), + before=( + ohostedcons.Stages.DIALOG_TITLES_E_NETWORK, + ), + condition=lambda self: self._enable, + name=ohostedcons.Stages.CONFIG_CLOUD_INIT_VM_NETWORKING, + ) + def _customize_vm_networking(self): + interactive = self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_STATIC_CIDR + ] is None + + if interactive: + while self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_STATIC_CIDR + ] is None: + static = self.dialog.queryString( + name='CI_VM_STATIC_NETWORKING', + note=_( + 'Rely on DHCP to configure the network for the ' + 'engine VM?\n' + '(@VALUES@)[@DEFAULT@]? ' + ), + prompt=True, + validValues=(_('DHCP'), _('Static')), + caseSensitive=False, + default=_('DHCP') + ) == _('Static').lower() + if static: # Static + # TODO: construct a proper one based on the host one! + default_cidr = '192.168.1.100/24' + ipcidr = self.dialog.queryString( + name='CI_CIDR', + note=_( + 'Please enter the IP address/prefix len ' + 'to be used for the engine VM\n' + '[@DEFAULT@] ' + ), + prompt=True, + caseSensitive=False, + default=default_cidr, + ) + valid_ip = self._validate_ip_cidr(ipcidr) + if not valid_ip: + self.logger.error( + _( + "'{ipcidr}' is not a valid CIDR " + "IP address" + ).format( + ipcidr=ipcidr + ) + ) + break + + self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_CIDR + ] = ipcidr + + # TODO: validate that the gateway will be in the same subnet + # TODO: ask for DNS + # TODO: ask if the user want to push host hostname under + # /etc/hosts on the VM + + else: # DHCP + self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_CIDR + ] = False + else: + if self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_CIDR + ]: + valid_ip = self._validate_ip_cidr( + self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_CIDR + ] + ) + if not valid_ip: + msg = _( + "'{ipcidr}' is not a valid CIDR " + "IP address" + ).format( + ipcidr=self.environment[ + ohostedcons.VMEnv.CLOUD_INIT_VM_CIDR + ] + ) + self.logger.error( + msg + ) + raise RuntimeError(msg) @plugin.event( stage=plugin.Stages.STAGE_MISC, @@ -336,11 +475,12 @@ f.write(user_data) f.close() - meta_data = '' + meta_data = 'instance-id: {instance}\n'.format( + instance=self.environment[ohostedcons.VMEnv.VM_UUID], + ) f_meta_data = os.path.join(self._directory_name, 'meta-data') if self.environment[ohostedcons.VMEnv.CLOUD_INIT_INSTANCE_HOSTNAME]: - meta_data = ( - 'instance-id: {instance}\n' + meta_data += ( 'local-hostname: {hostname}\n' ).format( instance=self.environment[ @@ -350,6 +490,29 @@ ohostedcons.VMEnv.CLOUD_INIT_INSTANCE_HOSTNAME ], ) + + if self.environment[ohostedcons.VMEnv.CLOUD_INIT_VM_STATIC_CIDR]: + ip = netaddr.IPNetwork( + self.environment[ohostedcons.VMEnv.CLOUD_INIT_VM_STATIC_CIDR] + ) + meta_data += ( + 'network-interfaces: |\n' + ' iface eth0 inet static\n' + ' address {ip_addr}\n' + ' network {network}\n' + ' netmask {netmask}\n' + ' broadcast {broadcast}\n' + ' gateway {gateway}\n' + ).format( + ip_addr=ip.ip, + network=ip.network, + netmask=ip.netmask, + broadcast=ip.broadcast, + gateway=self.environment[ + ohostedcons.NetworkEnv.GATEWAY + ], + ) + f = open(f_meta_data, 'w') f.write(meta_data) f.close() -- To view, visit https://gerrit.ovirt.org/41357 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic09f4d92e44f1bf810f06ada703e533b8c5e2061 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-hosted-engine-setup Gerrit-Branch: master Gerrit-Owner: Simone Tiraboschi <stira...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches