Apr 30 2018

Practical Tips for SPARC: Automatically Configuring Solaris Environments Using Puppet (Part 2)

Nowadays, we are seeing more and more instances of virtual environments being installed in a private cloud. Since these virtual environments are in many cases similarly configured, it makes sense to automate the configuration procedure. Part 2 of this blog provides a practical example of how to automatically configure a Solaris Zone with Puppet.

More specifically, I will show you how to automatically install a so-called non-global zone (hereinafter, NGZ).

Preparation

Although you can configure a portion of the NGZ automatically using only a manifest, this method falls short of achieving full automation. In this blog, I will automate the full installation procedure with a zone config file and sc_profile file as a template.

Note: When you use an Oracle VM for the SPARC domain, set the vnet for the guest domain to generate a Mac address for the vnic of the NGZ as below.

# ldm set-vnet alt-mac-addrs=auto <vnet> <guest domain>

Below is a template for the zone config file. The variable "%{zonename}" is set to the parameter value of the provider. The numbers of CPU of "dedicated-cpu" is a variable and retrieved from the manifest.

create -b

set brand=solaris

set zonepath=/zones/%{zonename}

set ip-type=exclusive

set autoboot=false

add dedicated-cpu

set ncpus=<%= @ncpus %>

end

add anet

set linkname=net0

set lower-link=auto

set configure-allowed-address=true

set link-protection=mac-nospoof

set mac-address=auto

end

Following next is a template for the sc_config file which is created using the sysconfig command. Replace the host name with a variable <%= @nname %>, IP address with a variable <%= @ip %> and default router with a variable <%= @defaultroute %>. Values are retrieved from the manifest.

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">

<!-- Auto-generated by sysconfig -->

<service_bundle type="profile" name="sysconfig">

<service version="1" type="service" name="system/identity">

<instance enabled="true" name="node">

<property_group type="application" name="config">

<propval type="astring" name="nodename" value="<%= @nname %>"/>

</property_group>

</instance>

</service>

<service version="1" type="service" name="network/install">

<instance enabled="true" name="default">

<property_group type="application" name="install_ipv6_interface">

<propval type="astring" name="stateful" value="yes"/>

<propval type="astring" name="address_type" value="addrconf"/>

<propval type="astring" name="name" value="net0/v6"/>

<propval type="astring" name="stateless" value="yes"/>

</property_group>

<property_group type="application" name="install_ipv4_interface">

<propval type="net_address_v4" name="static_address" value="<%= @ip %>"/>

<propval type="astring" name="name" value="net0/v4"/>

<propval type="astring" name="address_type" value="static"/>

<propval type="net_address_v4" name="default_route" value="<%= @defaultroute %>"/>

</property_group>

</instance>

</service>

<service version="1" type="service" name="network/physical">

<instance enabled="true" name="default">

<property_group type="application" name="netcfg">

<propval type="astring" name="active_ncp" value="DefaultFixed"/>

</property_group>

</instance>

</service>

<service version="1" type="service" name="system/name-service/switch">

<property_group type="application" name="config">

<propval type="astring" name="default" value="files"/>

</property_group>

<instance enabled="true" name="default"/>

</service>

<service version="1" type="service" name="system/name-service/cache">

<instance enabled="true" name="default"/>

</service>

<service version="1" type="service" name="system/keymap">

<instance enabled="true" name="default">

<property_group type="application" name="keymap">

<propval type="astring" name="layout" value="Japanese"/>

</property_group>

</instance>

</service>

<service version="1" type="service" name="system/timezone">

<instance enabled="true" name="default">

<property_group type="application" name="timezone">

<propval type="astring" name="localtime" value="Asia/Tokyo"/>

</property_group>

</instance>

</service>

<service version="1" type="service" name="system/environment">

<instance enabled="true" name="init">

<property_group type="application" name="environment">

<propval type="astring" name="LANG" value="ja_JP.UTF-8"/>

</property_group>

</instance>

</service>

<service version="1" type="service" name="system/config-user">

<instance enabled="true" name="default">

<property_group type="application" name="root_account">

<propval type="astring" name="type" value="role"/>

<propval type="astring" name="login" value="root"/>

<propval type="astring" name="password" value="$5$fU7qnOGX$bKeHN9pVv59io.VqKoHUT0hvYM8aqO1KKx1ApLAc5Q9"/>

</property_group>

<property_group type="application" name="user_account">

<propval type="astring" name="roles" value="root"/>

<propval type="astring" name="shell" value="/usr/bin/bash"/>

<propval type="astring" name="login" value="user01"/>

<propval type="astring" name="password" value="$5$7C9TC5nf$M1T.9Q5Kxb9R3g/VHfweh6H7.z2HmXcM5VSjZUcbu52"/>

<propval type="astring" name="type" value="normal"/>

<propval type="astring" name="sudoers" value="ALL=(ALL) ALL"/>

<propval type="count" name="gid" value="10"/>

<propval type="astring" name="description" value=""/>

<propval type="astring" name="profiles" value="System Administrator"/>

</property_group>

</instance>

</service>

<service version="1" type="service" name="system/fm/asr-notify">

<instance enabled="true" name="default"/>

</service>

<service version="1" type="service" name="system/ocm">

<instance enabled="true" name="default">

<property_group type="application" name="reg">

<propval type="astring" name="user" value=""/>

</property_group>

</instance>

</service>

</service_bundle>

Put the template files in the directory "/etc/puppet/modules/<module name>/templates" on the master node. For the purposes of this blog, specify the module name as "zone", and save the zone config file as "myzone.cfg" and the sc_config file as "myzone_sc.xml". Note that file names should be written as "<module name>/<file name>" in the manifest.

Creating the Manifest

The contents of the manifest are below.

node 'doagent' {

$sc_conf = '/tmp/myzone_sc.xml'

$zone_conf = '/tmp/myzone.cfg'

$nname = 'myzone'

$ip = '10.20.98.127/24'

$defaultroute = '10.20.98.1'

$ncpus = '1'

file { $sc_conf :

mode => 666,

owner => root,

group => root,

content => template('zone/myzone_sc.xml'),

ensure => 'present'

}

->

file { $zone_conf :

mode => 666,

owner => root,

group => root,

content => template('zone/myzone.cfg'),

ensure => 'present'

}

->

zone { $nname :

config_profile => $sc_conf,

zonecfg_export => $zone_conf,

name => $nname,

ensure => 'running'

}

}

node default {

}

In the next section, I will explain the manifest.

node 'doagent' {

Run only on the machine whose host name is "doagent".

$sc_conf = '/tmp/myzone_sc.xml'

$zone_conf = '/tmp/myzone.cfg'

Words that start with a '$' are user-defined variables. Set the temporary file names for the zone config file and the sc_profile file for each variable.

$nname = 'myzone'

$ip = '10.20.98.127/24'

$defaultroute = '10.20.98.1'

$ncpus = '1'

Set the zone name, IP address, default router and number of CPU for each variable.

file { $sc_conf :

mode => 666,

owner => root,

group => root,

content => template('zone/myzone_sc.xml'),

ensure => 'present'

}

->

file { $zone_conf :

mode => 666,

owner => root,

group => root,

content => template('zone/myzone.cfg'),

ensure => 'present'

}

Copy these files to the agent node, since Puppet agents can only refer to a local file. At that time, the variable of the template is replaced to the settings value.

zone { $nname :

config_profile => $sc_conf,

zonecfg_export => $zone_conf,

name => $nname,

ensure => 'running'

}

Create the NGZ using the files copied to the agent node. For our purposes, let the NGZ status is "running".

node default {

}

In this entry, describe the settings that apply to all nodes. Otherwise, the Puppet process will fail.

Running the Manifest

Run the manifest referring to the previous section. While you do, the NGZ creation process continues in the background. This may take several minutes. Check the status with the zoneadm command as is shown below. When the status of "myzone" changes to "running", all procedures are completed.

root@doagent:~# zoneadm list -vc

ID NAME STATUS PATH BRAND IP

0 global running / solaris shared

1 myzone running /zones/myzone solaris excl

When the process ends, log in and check that all works normally.

Running Puppet Periodically

Since the Puppet agent is also registered as an SMF service, it can be run periodically by setting the service to "online". Check the status of the Puppet agent service. The initial status is "disable".

root@doagent:~# svcs puppet:agent

STATE STIME FMRI

disable 10:14:52 svc:/application/puppet:agent

After configuration, start service with svcadm command.

root@doagent:~# svcadm enable puppet:agent

Check the status to be "online" with svcs command.

root@doagent:~# svcs puppet puppet:master

STATE STIME FMRI

online 10:44:52 svc:/application/puppet:agent

Latest manifests are run every 30 minutes.

In this blog, I have given one usage example for Puppet. Since Puppet has several other functions as well, I will share other examples with you in the future. As always, I welcome your feedback, tips and comments.

Disclaimer

The information contained in this blog is for general information purposes only. While we endeavour to keep the information up-to-date and correct through testing on a practical system, we make no warranties of any kind about the completeness, accuracy, reliability, suitability or availability. Any reliance you place on such information is strictly at your own risk. – The information in this blog is subject to change without notice.

Shinichiro Asai