From a9bbbc6e6455c9fd9b9bd18b90ce5422af0d6e3c Mon Sep 17 00:00:00 2001 From: Steven Hillman Date: Fri, 21 Aug 2015 11:56:02 -0700 Subject: [PATCH] Add pacemaker integration code into VSM puppetry This patch adds in the option to support pacemaker integration in OSP7. Specifically when pacemaker integration is enabled two VMs will be created- one for the primary, and one for the secondary. Neither VM will be defined or started. Addditionally MACs will be generated for both VMs to prevent an issue on VSM switchover. Code was also added to support cases where the VSM needs to be brought up in setups where there's an existing bridge. Change-Id: I2ca2ccc12a9db56348440d210eef4bde25142aef --- manifests/deploy.pp | 67 ++++++++++++++++++---- manifests/init.pp | 29 +++++++++- manifests/pkgprep_ovscfg.pp | 86 +++++++++++++++------------- manifests/vsmprep.pp | 21 ++++--- templates/vsm_vm.xml.erb | 9 +++ templates/vsm_vm_secondary.xml.erb | 92 ++++++++++++++++++++++++++++++ 6 files changed, 245 insertions(+), 59 deletions(-) create mode 100644 templates/vsm_vm_secondary.xml.erb diff --git a/manifests/deploy.pp b/manifests/deploy.pp index b39afe6..d03d68e 100644 --- a/manifests/deploy.pp +++ b/manifests/deploy.pp @@ -5,14 +5,31 @@ # class n1k_vsm::deploy { + require n1k_vsm + include n1k_vsm + #ensure tap interfaces and deploy the vsm $ctrltap = 'vsm-ctrl0' $mgmttap = 'vsm-mgmt0' $pkttap = 'vsm-pkt0' + # Validate and get the array of digits for the vsm_mac_base (or use default) + # Using _vmb as the name for the final string to increase readability + $tmp_mac_base = regsubst($n1k_vsm::vsm_mac_base, '[^0-9a-fA-F]+', '') + if (inline_template('<%= @tmp_mac_base.length %>') < 7) { + $vmb = split('005dc79', '') + } else { + $vmb = split($tmp_mac_base, '') + } + + # Generate MACs for VSM + $ctrlmac = "52:54:${vmb[0]}${vmb[1]}:${vmb[2]}${vmb[3]}:${vmb[4]}${vmb[5]}:${vmb[6]}1" + $mgmtmac = "52:54:${vmb[0]}${vmb[1]}:${vmb[2]}${vmb[3]}:${vmb[4]}${vmb[5]}:${vmb[6]}2" + $pktmac = "52:54:${vmb[0]}${vmb[1]}:${vmb[2]}${vmb[3]}:${vmb[4]}${vmb[5]}:${vmb[6]}3" + exec { 'Exec_create_disk': command => "/usr/bin/qemu-img create -f raw ${n1k_vsm::diskfile} ${n1k_vsm::disksize}G", - unless => "/usr/bin/virsh list --all | grep -c ${n1k_vsm::vsmname}", + creates => $n1k_vsm::diskfile, } $targetxmlfile = "/var/spool/cisco/vsm/vsm_${n1k_vsm::vsm_role}_deploy.xml" @@ -21,19 +38,49 @@ class n1k_vsm::deploy owner => 'root', group => 'root', mode => '0666', + seltype => 'virt_content_t', content => template('n1k_vsm/vsm_vm.xml.erb'), require => Exec['Exec_create_disk'], } - exec { 'Exec_Define_VSM': - command => "/usr/bin/virsh define ${targetxmlfile}", - unless => "/usr/bin/virsh list --all | grep -c ${n1k_vsm::vsmname}", - } + # Don't start VSM if this is pacemaker controlled deployment + if !($n1k_vsm::pacemaker_control) { + exec { 'Exec_Define_VSM': + command => "/usr/bin/virsh define ${targetxmlfile}", + unless => "/usr/bin/virsh list --all | grep -c ${n1k_vsm::vsmname}", + require => File['File_Target_XML_File'], + } - exec { 'Exec_Launch_VSM': - command => "/usr/bin/virsh start ${n1k_vsm::vsmname}", - unless => "/usr/bin/virsh list --all | grep ${n1k_vsm::vsmname} | grep -c running", - } + exec { 'Exec_Launch_VSM': + command => "/usr/bin/virsh start ${n1k_vsm::vsmname}", + unless => ("/usr/bin/virsh list --all | grep ${n1k_vsm::vsmname} | grep -c running"), + require => Exec['Exec_Define_VSM'], + } + } else { + # For pacemker controlled deployment, set up the secondary VSM as well + # ensure tap interfaces and deploy the vsm + $ctrltap_s = 'vsm-ctrl1' + $mgmttap_s = 'vsm-mgmt1' + $pkttap_s = 'vsm-pkt1' + # Generate MACs + $ctrlmac_s = "52:54:${vmb[0]}${vmb[1]}:${vmb[2]}${vmb[3]}:${vmb[4]}${vmb[5]}:${vmb[6]}4" + $mgmtmac_s = "52:54:${vmb[0]}${vmb[1]}:${vmb[2]}${vmb[3]}:${vmb[4]}${vmb[5]}:${vmb[6]}5" + $pktmac_s = "52:54:${vmb[0]}${vmb[1]}:${vmb[2]}${vmb[3]}:${vmb[4]}${vmb[5]}:${vmb[6]}6" - Exec['Exec_create_disk'] -> File['File_Target_XML_File'] -> Exec['Exec_Define_VSM'] -> Exec['Exec_Launch_VSM'] + exec { 'Exec_create_disk_Secondary': + command => "/usr/bin/qemu-img create -f raw ${n1k_vsm::diskfile_s} ${n1k_vsm::disksize}G", + creates => $n1k_vsm::diskfile_s, + } + + $targetxmlfile_s = "/var/spool/cisco/vsm/vsm_${n1k_vsm::vsm_role_s}_deploy.xml" + file { 'File_Target_XML_File_Secondary': + path => $targetxmlfile_s, + owner => 'root', + group => 'root', + mode => '0666', + seltype => 'virt_content_t', + content => template('n1k_vsm/vsm_vm_secondary.xml.erb'), + require => Exec['Exec_create_disk_Secondary'], + } + } } diff --git a/manifests/init.pp b/manifests/init.pp index 13307a4..261b30c 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -36,6 +36,19 @@ # [*n1kv_version*] # (required) Version of the Nexus1000v VSM # +# [*pacemaker_control*] +# (optional) Set to determine if pacemaker will control the VSM. If true will deploy both +# primary and secondary VSMs on all nodes and will not start VSM. Defaults to false and +# thus is optional unless this functionality is being used. +# +# [*existing_bridge*] +# (required) If VSM should be installed behind an existing bridge, this should be set to +# true and the bridge name should be provided in phy_if_bridge. +# +# [*vsm_mac_base*] +# (optional) If set, provides randomization for the MAC addresses for the VSM VM(s). +# Should be a (random) hexadecimal number of at least 7 digits (more is fine). +# class n1k_vsm( $n1kv_source = '', $n1kv_version = 'latest', @@ -47,6 +60,9 @@ class n1k_vsm( $vsm_mgmt_ip, $vsm_mgmt_netmask, $vsm_mgmt_gateway, + $pacemaker_control = false, + $existing_bridge = false, + $vsm_mac_base = '' ) { if($::osfamily != 'Redhat') { @@ -55,6 +71,15 @@ class n1k_vsm( fail("Unsupported osfamily ${::osfamily}") } + # Ensure role is set to primary for pacemaker controlled deployment + # Additionally setup the extra variables for the secondary VSM + if ($n1k_vsm::pacemaker_control) { + $vsm_role_s = 'secondary' + $vsmname_s = 'vsm-s' + $imgfile_s = "/var/spool/cisco/vsm/${vsm_role_s}_repacked.iso" + $diskfile_s = "/var/spool/cisco/vsm/${vsm_role_s}_disk" + } + if ($n1k_vsm::vsm_role == 'primary') or ($n1k_vsm::vsm_role == 'standalone') { $vsmname = 'vsm-p' $mgmtip = $vsm_mgmt_ip @@ -73,7 +98,9 @@ class n1k_vsm( $disksize = 4 $imgfile = "/var/spool/cisco/vsm/${n1k_vsm::vsm_role}_repacked.iso" $diskfile = "/var/spool/cisco/vsm/${n1k_vsm::vsm_role}_disk" - $ovsbridge = 'vsm-br' + + #Set bridge name properly + $ovsbridge = 'vsm-br' #VSM installation will be done only once. Will not respond to puppet sync $_phy_if_bridge = regsubst($n1k_vsm::phy_if_bridge, '[.:-]+', '_', 'G') diff --git a/manifests/pkgprep_ovscfg.pp b/manifests/pkgprep_ovscfg.pp index 073fd98..5705a3d 100644 --- a/manifests/pkgprep_ovscfg.pp +++ b/manifests/pkgprep_ovscfg.pp @@ -19,7 +19,7 @@ class n1k_vsm::pkgprep_ovscfg # VSM dependent packages installation section package { 'Package_qemu-kvm': ensure => installed, - name => 'qemu-kvm', + name => 'qemu-kvm-rhev', } package {'Package_libvirt': @@ -64,8 +64,11 @@ class n1k_vsm::pkgprep_ovscfg notify { "Debug br ${n1k_vsm::ovsbridge} intf ${n1k_vsm::phy_if_bridge} ." : withpath => true } notify { "Debug ${n1k_vsm::vsmname} ip ${n1k_vsm::phy_ip_addr} mask ${n1k_vsm::phy_ip_mask} gw_intf ${n1k_vsm::gw_intf}" : withpath => true } - # Check if we've already configured the ovs - if $n1k_vsm::gw_intf != $n1k_vsm::ovsbridge { + $_ovsbridge = regsubst($n1k_vsm::ovsbridge, '[.:-]+', '_', 'G') + $_ovsbridge_mac = inline_template("<%= scope.lookupvar('::macaddress_${_ovsbridge}') %>") + + # Check if we've already configured the vsm bridge, skip configuration if so + if ($_ovsbridge_mac == '') { # Modify Ovs bridge inteface configuation file augeas { 'Augeas_modify_ifcfg-ovsbridge': name => $n1k_vsm::ovsbridge, @@ -87,47 +90,50 @@ class n1k_vsm::pkgprep_ovscfg 'set USERCTL no', ], } - - # Modify Physical Interface config file - augeas { 'Augeas_modify_ifcfg-phy_if_bridge': - name => $n1k_vsm::phy_if_bridge, - context => "/files/etc/sysconfig/network-scripts/ifcfg-${n1k_vsm::phy_if_bridge}", - changes => [ - 'set TYPE OVSPort', - "set DEVICE ${n1k_vsm::phy_if_bridge}", - 'set DEVICETYPE ovs', - "set OVS_BRIDGE ${n1k_vsm::ovsbridge}", - 'set NM_CONTROLLED no', - 'set BOOTPROTO none', - 'set ONBOOT yes', - "set NAME ${n1k_vsm::phy_if_bridge}", - 'set DEFROUTE no', - 'set IPADDR ""', - 'rm NETMASK', - 'rm GATEWAY', - 'set USERCTL no', - ], - } - exec { 'Flap_n1kv_phy_if': - command => "/sbin/ifdown ${n1k_vsm::phy_if_bridge} && /sbin/ifup ${n1k_vsm::phy_if_bridge}", - require => augeas['Augeas_modify_ifcfg-phy_if_bridge'], - } exec { 'Flap_n1kv_bridge': command => "/sbin/ifdown ${n1k_vsm::ovsbridge} && /sbin/ifup ${n1k_vsm::ovsbridge}", - require => augeas['Augeas_modify_ifcfg-ovsbridge'], + require => Augeas['Augeas_modify_ifcfg-ovsbridge'], } - # Make sure that networking comes fine after reboot- add init file and restart networking - file { 'Create_Init_File': - replace => 'yes', - path => '/etc/init.d/n1kv', - owner => 'root', - group => 'root', - mode => '0775', - source => 'puppet:///modules/n1k_vsm/n1kv', - require => exec['Flap_n1kv_phy_if', 'Flap_n1kv_bridge'], - notify => Service['Service_network'], + + if !($n1k_vsm::existing_bridge) { + # If there isn't an existing bridge, the interface is a port, and we + # need to add it to vsm-br + # Modify Physical Interface config file + augeas { 'Augeas_modify_ifcfg-phy_if_bridge': + name => $n1k_vsm::phy_if_bridge, + context => "/files/etc/sysconfig/network-scripts/ifcfg-${n1k_vsm::phy_if_bridge}", + changes => [ + 'set TYPE OVSPort', + "set DEVICE ${n1k_vsm::phy_if_bridge}", + 'set DEVICETYPE ovs', + "set OVS_BRIDGE ${n1k_vsm::ovsbridge}", + 'set NM_CONTROLLED no', + 'set BOOTPROTO none', + 'set ONBOOT yes', + "set NAME ${n1k_vsm::phy_if_bridge}", + 'set DEFROUTE no', + 'set IPADDR ""', + 'rm NETMASK', + 'rm GATEWAY', + 'set USERCTL no', + ], + } + exec { 'Flap_n1kv_phy_if': + command => "/sbin/ifdown ${n1k_vsm::phy_if_bridge} && /sbin/ifup ${n1k_vsm::phy_if_bridge}", + require => Augeas['Augeas_modify_ifcfg-phy_if_bridge'], + } + } else { + # If there is an existing bridge- create patch ports to connect vsm-br to it + exec { 'Create_patch_port_on_existing_bridge': + command => "/bin/ovs-vsctl --may-exist add-port ${n1k_vsm::phy_if_bridge} ${n1k_vsm::phy_if_bridge}-${n1k_vsm::ovsbridge} -- set Interface ${n1k_vsm::phy_if_bridge}-${n1k_vsm::ovsbridge} type=patch options:peer=${n1k_vsm::ovsbridge}-${n1k_vsm::phy_if_bridge}", + require => Exec['Flap_n1kv_bridge'], + } + exec { 'Create_patch_port_on_vsm_bridge': + command => "/bin/ovs-vsctl --may-exist add-port ${n1k_vsm::ovsbridge} ${n1k_vsm::ovsbridge}-${n1k_vsm::phy_if_bridge} -- set Interface ${n1k_vsm::ovsbridge}-${n1k_vsm::phy_if_bridge} type=patch options:peer=${n1k_vsm::phy_if_bridge}-${n1k_vsm::ovsbridge}", + require => Exec['Flap_n1kv_bridge'], + } } - } # endif of if "${n1k_vsm::gw_intf}" != "${n1k_vsm::ovsbridge}" + } # endif of if "${n1k_vsm::gw_intf}" != "${n1k_vsm::ovsbridge}" or ($n1k_vsm::existing_bridge == 'true') } 'Ubuntu': { } diff --git a/manifests/vsmprep.pp b/manifests/vsmprep.pp index f704666..d356a06 100644 --- a/manifests/vsmprep.pp +++ b/manifests/vsmprep.pp @@ -35,12 +35,9 @@ class n1k_vsm::vsmprep } } else { $vsmimage_uri = 'unspec' + $vsm_path = '/opt/cisco/vsm' } -# exec { 'Prev_VSM': -# command => "/bin/rm -f /var/spool/cisco/vsm/* || /bin/true", -# } - if $vsmimage_uri == 'file' { #specify location on target-host where image file will be downloaded to. file { $vsmtgtimg: @@ -63,8 +60,9 @@ class n1k_vsm::vsmprep } } package {'nexus-1000v-iso': - ensure => $n1k_vsm::n1kv_version, - name => 'nexus-1000v-iso' + ensure => $n1k_vsm::n1kv_version, + name => 'nexus-1000v-iso', + provider => 'yum', } } @@ -80,8 +78,15 @@ class n1k_vsm::vsmprep # Now generate ovf xml file and repackage the iso exec { 'Exec_VSM_Repackage_Script': - command => "/tmp/repackiso.py -i${vsm_path}/n1000v-dk9.${n1k_vsm::n1kv_version}.iso -d${n1k_vsm::vsm_domain_id} -n${n1k_vsm::vsmname} -m${n1k_vsm::mgmtip} -s${n1k_vsm::mgmtnetmask} -g${n1k_vsm::mgmtgateway} -p${n1k_vsm::vsm_admin_passwd} -r${n1k_vsm::vsm_role} -f/var/spool/cisco/vsm/${n1k_vsm::vsm_role}_repacked.iso ", - unless => "/usr/bin/virsh list --all | grep -c ${n1k_vsm::vsmname}", + command => "/tmp/repackiso.py -i${vsm_path}/n1000v-dk9.${n1k_vsm::n1kv_version}.iso -d${n1k_vsm::vsm_domain_id} -n${n1k_vsm::vsmname} -m${n1k_vsm::mgmtip} -s${n1k_vsm::mgmtnetmask} -g${n1k_vsm::mgmtgateway} -p${n1k_vsm::vsm_admin_passwd} -r${n1k_vsm::vsm_role} -f/var/spool/cisco/vsm/${n1k_vsm::vsm_role}_repacked.iso", + creates => "/var/spool/cisco/vsm/${n1k_vsm::vsm_role}_repacked.iso", } + # If we're under pacemaker_control, create a secondary VSM iso as well + if ($n1k_vsm::pacemaker_control) { + exec { 'Exec_VSM_Repackage_Script_secondary': + command => "/tmp/repackiso.py -i${vsm_path}/n1000v-dk9.${n1k_vsm::n1kv_version}.iso -d${n1k_vsm::vsm_domain_id} -n${n1k_vsm::vsmname_s} -m${n1k_vsm::mgmtip} -s${n1k_vsm::mgmtnetmask} -g${n1k_vsm::mgmtgateway} -p${n1k_vsm::vsm_admin_passwd} -r${n1k_vsm::vsm_role_s} -f/var/spool/cisco/vsm/${n1k_vsm::vsm_role_s}_repacked.iso", + creates => "/var/spool/cisco/vsm/${n1k_vsm::vsm_role_s}_repacked.iso", + } + } } diff --git a/templates/vsm_vm.xml.erb b/templates/vsm_vm.xml.erb index 82a2a01..7096724 100644 --- a/templates/vsm_vm.xml.erb +++ b/templates/vsm_vm.xml.erb @@ -41,6 +41,9 @@ + <% if scope.lookupvar('n1k_vsm::pacemaker_control') == true %> + + <% end %>
@@ -49,6 +52,9 @@ + <% if scope.lookupvar('n1k_vsm::pacemaker_control') == true %> + + <% end %>
@@ -57,6 +63,9 @@ + <% if scope.lookupvar('n1k_vsm::pacemaker_control') == true %> + + <% end %>
diff --git a/templates/vsm_vm_secondary.xml.erb b/templates/vsm_vm_secondary.xml.erb new file mode 100644 index 0000000..cbd237b --- /dev/null +++ b/templates/vsm_vm_secondary.xml.erb @@ -0,0 +1,92 @@ + + <%= scope.lookupvar('n1k_vsm::vsmname_s') %> + <%= scope.lookupvar('n1k_vsm::memory') %> + <%= scope.lookupvar('n1k_vsm::vcpu') %> + + + hvm + + + + + + + + destroy + restart + restart + + + /usr/libexec/qemu-kvm + + + '/> + + + + + + '/> + + + + + + +
+ + + + '/> + + + + <% if scope.lookupvar('n1k_vsm::pacemaker_control') == true %> + + <% end %> +
+ + + + '/> + + + + <% if scope.lookupvar('n1k_vsm::pacemaker_control') == true %> + + <% end %> +
+ + + + '/> + + + + <% if scope.lookupvar('n1k_vsm::pacemaker_control') == true %> + + <% end %> +
+ + + + + + + + +