Puppet Class: mq_install::fixpack

Defined in:
manifests/fixpack.pp

Summary

The defined type `mq_install::fixoack` allows you to install specified fixpacks on your system.

Overview

mq_install::fixpack

The fixpacks will be added on top of your software installation managed by [‘mq_install::software`](./software).

The simples way to use it is:

“‘ puppet mq_install::fixpack

source_locaation => '/nfs_share/software'

“‘ Based on this puppet code, Puppet will install fixpack 9.1.0.1. Because the installation of the fixpack requires all MQ processes to be stopped, this code will stop ALL MQ managers when it finds it needs to install the fixpack.

When the ‘mq_install::fixpack’ is part of a larger set of Puppet code also managing MQ managers and queues, that definition will restart the required MQ queue managers.

## Fixpack updates

When you specify a higher fixpack version, Puppet will detect this and start the fixpack upgrade scenario. The upgrade scenario consists of:

1) Shutting down all running queue managers 2) Installing the requested fixpack

WARNING The ‘mq_install::fixpack` class does not automatically restart the queue managers again. In general, this is taken care of by `mq_install::autostart`. If `mq_install::autostart` is not part of your manifest, you must ensure your own steps to make sure the queue managers are restarted again. ## Fixpack rollback

When you specify a fixpack version that is lower than the fixpack that is currently installed, Puppet will detect this and start the rollback procedure. Puppet supports rolling one fixpack at a time. This means that Puppet will only allow you to rollback (e.g., uninstall) the latest installed fixpack.

Puppet will throw an error when:

  • You specified a lower version than currenly installed, but also a fixpack version that was not previously installed.

  • You specified a lower version than currenly installed, but a version that is older than the previous fixpack version that was installed.

See the file “LICENSE” for the full license governing this code.

Parameters:

  • version (String[1])

    The title of his resource is used to specify the required version of the fixpack to be installed. It can for example be ‘9.1.0.1`.

  • service_window (String[1]) (defaults to: 'INSTALL_ONLY')

    The service_window Puppet will use to execute a specified upgrade. When Puppet detects a mismatch between the current version and the version in your manifest, it will start to execute an upgrade. But in general, you want some control over when that happens. You don’t want Puppet to stop your queue managers during regular production hours to do the upgrade. The ‘service_window` parameter allows this control. The parameter can have the following values:

    • DIRECT

    • INSTALL_ONLY

    • WHEN_NOT_RUNNING

    • A time range

    ## DIRECT ‘DIRECT` is the normal behavior of Puppet (e.g., not the default of the parameter). When a manifest change is detected, Puppet will immediately execute the upgrade and, in this process, stop the MQ queue managers. ## INSTALL_ONLY This is the default value for this class. In this case, Puppet will use the specified manifest values ONLY on an initial install. When Puppet detects MQ is already running, it will leave it like it is and NOT do the upgrade. You can use, for example, a bolt plan or task to execute the upgrade at a moment that suits your requirements. ## WHEN_NOT_RUNNING Only apply this class when there is no queue manager running. ## time range When you have a specific service window wherein Puppet is allowed to do the MQ shutdown and execute the upgrade procedure, you can specify a time range. An example of a time range would be: ’01:00 - 02:00`

  • source_location (String[1])

    The location of the MQ software. Here is an example on how to use this:

    class { '::mq_install::...':
      ...
      source_location => '/software',
      ...
    }
    
  • tmp_dir (String[1]) (defaults to: '/tmp')

    This defined type uses a temporary directory. By default this is ‘tmp`. If you want to use an other directory for this, you must specify this parameter. Here is an example on how to use this:

    class { '::mq_install::...':
      ...
      tmp_dir => '/my_tmp_dir',
      ...
    }
    

    On systems with a secured ‘/tmp` direcory, you MUST specify the `tmp_dir` parameter and specify a directory that puppet is allowed to execute scripts from. It must also have enough space to receive the extracted MQ installation kit.

  • logoutput (Variant[Enum['on_failure'], Boolean]) (defaults to: 'on_failure')

    If you want to see the output of the ‘exec` resources in the type, you can set this value to `true`. The default is `on_failure`. Here is an example on how to use this:

    class { '::mq_install::...':
      ...
      logoutput => true,
      ...
    }
    


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'manifests/fixpack.pp', line 89

class mq_install::fixpack (
  String[1]                            $version,
  String[1]                            $source_location,
  String[1]                            $service_window     = 'INSTALL_ONLY',  # If needed the service window to apply or maybe value 'INSTALL_ONLY' or 'DIRECT'
  String[1]                            $tmp_dir            = '/tmp',          # Directory used for unpacking
  Variant[Enum['on_failure'], Boolean] $logoutput          = 'on_failure',    # Output of the execs
) {
  mq_install { "mq_install::fixpack::${version}": }

  if $facts['mq_managers'] {
    $running_queue_managers =  $facts['mq_managers'].filter |$qm| { $qm['state'] in ['Running', 'Running as standby'] }
  } else {
    $running_queue_managers = []
  }
  $version_components = $version.split('\.')
  #
  # On the package version the last number is separated by an dash
  #
  $package_version = case $facts['kernel'] {
    'Linux':  { "U${version_components[0]}${version_components[1]}${version_components[2]}${version_components[3]}-${version_components[0]}.${version_components[1]}.${version_components[2]}-${version_components[3]}" }
    'SunOS':  { sprintf('U%02d%02d%04d', $version_components[0], $version_components[1], $version_components[3]) }
    'AIX':    { "U${version_components[0]}${version_components[1]}${version_components[2]}${version_components[3]}" }
    default:  {
      fail "Kernel ${facts['kernel']} is not (yet) supported by the mq_install module."
    }
  }
  $requested_fixpack = case $facts['kernel'] {
    'Linux':  { sprintf('U%1d%1d%02d', $version_components[0], $version_components[1], $version_components[3]) }
    'SunOS':  { sprintf('mqm-%02d-%02d-%02d-%02d', $version_components[0], $version_components[1], $version_components[2], $version_components[3]) }
    'AIX':    { sprintf('U%1d%1d%02d', $version_components[0], $version_components[1], $version_components[3]) }
    default:  {
      fail "Kernel ${facts['kernel']} is not (yet) supported by the mq_install module."
    }
  }
  #
  # Determine the file name of the FixPack. We use the standard files names used by IBM
  #
  $file_name = case $facts['kernel'] {
    'Linux': { sprintf('%1d.%1d.%1d-IBM-MQ-LinuxX64-FP%04d.tar.gz', $version_components[0], $version_components[1], $version_components[2], $version_components[3]) }
    'SunOS': {
      case $facts.dig('os','architecture') {
        'i86pc' : { "${version_components[0]}.${version_components[1]}.${version_components[2]}-IBM-MQ-SolarisX64-FP000${version_components[3]}.tar.Z" }
        default:  { "${version_components[0]}.${version_components[1]}.${version_components[2]}-IBM-MQ-SolarisSparc-FP000${version_components[3]}.tar.Z" }
      }
    }
    'AIX': { sprintf('%1d.%1d.%1d-IBM-MQ-AIX-FP%04d.tar.gz', $version_components[0], $version_components[1], $version_components[2], $version_components[3]) }
    default:  {
      fail "Kernel ${facts['kernel']} is not (yet) supported by the mq_install module."
    }
  }

  easy_type::debug_evaluation() # Show local variable on extended debug

  #
  # We support applying an update only in a specific service window. We also have three other options:
  #
  # 'WHEN_NOT_RUNNING' -> Only apply this class when there is no queue manager running
  #
  # 'INSTALL_ONLY' -> Only apply this class when the MQ software is not (yet) installed. This ensures 
  # an initial install always installes the latest specified version
  #
  # 'DIRECT' -> When  puppet deteects an update is needed it applies it directly. This is handy
  # when we apply this class from bolt or for test systems.
  # 
  # When the value is none of the predefined values, we use it to create a schedule.
  #

  case $service_window {
    'INSTALL_ONLY': {
      $service_schedule  = undef
      $condition = $facts['mq_version'] == 'not-installed'  # Apply this when not yet installed
      unless $condition {
        echo { 'When a fixpack update is detected, it will be skipped, because service window is set to INSTALL_ONLY':
          withpath => false,
        }
      }
    }
    'WHEN_NOT_RUNNING': {
      $service_schedule  = undef
      $condition = $running_queue_managers == []
      unless $condition {
        echo { 'When a fixpack update is detected, it will be skipped, because service window is set to WHEN_NOT_RUNNING and at least one queue manager is running':
          withpath => false,
        }
      }
    }
    'DIRECT': {
      echo { 'When a fixpack update is detected, it will take place directly without any schedule': withpath => false }
      $condition = true
      $service_schedule  = 'MQ_SOFTWARE_SERVICE_WINDOW'
      unless defined(Schedule['MQ_SOFTWARE_SERVICE_WINDOW']) {
        schedule { 'MQ_SOFTWARE_SERVICE_WINDOW':
          range  => '00:00 - 23:59:59',
        }
      }
    }
    default: {
      $condition = true
      $service_schedule  = 'MQ_SOFTWARE_SERVICE_WINDOW'
      if $facts['mq_version'] == 'not-installed' {
        echo { 'On intial install the fixpack will be applied regardless of schedule': withpath => false }
        # On intial installation ALWAYS directly apply the fixpack
        unless defined(Schedule['MQ_SOFTWARE_SERVICE_WINDOW']) {
          schedule { 'MQ_SOFTWARE_SERVICE_WINDOW':
            range  => '00:00 - 23:59:59',
          }
        }
      } else {
        echo { "When a fixpack update is detected, it will take place between ${service_window}": withpath => false }
        unless defined(Schedule['MQ_SOFTWARE_SERVICE_WINDOW']) {
          schedule { 'MQ_SOFTWARE_SERVICE_WINDOW':
            range  => $service_window,
          }
        }
      }
    }
  }

  if $condition {
    #
    # When we do a downgrade, check for some of the scenario's we don't support and report back 
    #
    if mq_install::fixpack_downgrade($facts['mq_version'], $version) {
      #
      # You can only roll back to an already installed fixpack. So if you request a fixpack version that is not in the list of 
      # installed fixpacks, we fail.
      #
      if !($requested_fixpack in $facts['mq_installed_fixpacks']) {
        fail "Requesting rollback to non-installed fixpack ${requested_fixpack} is not supported."
      }
      #
      # Whenever you request a version that is more than one fixpack ago, we block you from doing so.
      # Although this may be technically possible. This is not what we want to encourage by supporting it.
      # This functionality is meant to be used to do this. It is only meant to be used as a rollback scenario in case of an emergency
      #
      if $facts['mq_installed_fixpacks'][-2] != $requested_fixpack {
        fail 'Only rollback of one version is supported.'
      }
    }

    #
    # If the installed version is the same as the requested version. Do nothing
    #
    if mq_install::fixpack_upgrade($facts['mq_version'], $version) {
      debug 'Requested Fixpack upgrade'
      file { "${tmp_dir}/mq_fixpack_${version}":
        ensure   => 'directory',
        schedule => $service_schedule,
      }

      -> archive { "${tmp_dir}/${file_name}":
        ensure       => present,
        extract      => true,
        extract_path => "${tmp_dir}/mq_fixpack_${version}",
        source       => "${source_location}/${file_name}",
        creates      => "${tmp_dir}/mq_fixpack_${version}/crtmqfp",
        cleanup      => true,
        schedule     => $service_schedule,
      }

      #
      # MQ only allows us to install a fixpack package when no components
      # are running. So we have to stop all before continuing.
      #
      class { 'mq_install::internal::mq_stop':
        schedule  => $service_schedule,
        logoutput => $logoutput,
      }
      #
      # We need some of the variables also defined for installing software. That is why we (re) include the mq_install::software::unix
      #
      include mq_install::software

      case $facts['kernel'] {
        'Linux': {
          mq_install::internal::mq_packages { $package_version:
            packages        => $mq_install::software::selected_components,
            source_location => "${tmp_dir}/mq_fixpack_${version}",
            service_window  => $service_window,
            require         => Class['mq_install::internal::mq_stop'],
            schedule        => $service_schedule,
            before          => Exec["Remove temporary files for fixpack ${version}"],
          }
        }
        'SunOS': {
          $package_name = sprintf('mqm-%02d-%02d-%02d-%02d', $version_components[0], $version_components[1], $version_components[2], $version_components[3])

          file { "${tmp_dir}/mq_fixpack_${version}/${package_version}_answers":
            ensure   => 'file',
            content  => epp('mq_install/answers.epp', { 'selected_components' => $mq_install::software::selected_components }),
            schedule => $service_schedule,
          }

          -> exec { "install fixpack ${package_version}":
            command   => "pkgadd -n -r ${tmp_dir}/mq_fixpack_${version}/${package_version}_answers -a ${tmp_dir}/mq_fixpack_${version}/admin -d ${tmp_dir}/mq_fixpack_${version}/mqm-${package_version}.img ${package_name}",
            path      => '/usr/sbin',
            require   => Archive["${tmp_dir}/${file_name}"],
            before    => Exec["Remove temporary files for fixpack ${version}"],
            schedule  => $service_schedule,
            logoutput => $logoutput,
          }
        }
        default:  {
          fail "Kernel ${facts['kernel']} is not (yet) supported by the mq_install module."
        }
      }

      exec { "Remove temporary files for fixpack ${version}":
        path     => '/bin',
        command  => "rm -rf ${tmp_dir}/mq_fixpack_${version}",
        schedule => $service_schedule,
        onlyif   => "test -d ${tmp_dir}/mq_fixpack_${version}",
      }
      contain 'mq_install::internal::mq_stop'
    } elsif mq_install::fixpack_downgrade($facts['mq_version'], $version) {
      debug 'Requested Fixpack downgrade'
      #
      # MQ only allows us to install a fixpack package when no components
      # are running. So we have to stop all before continuing.
      #
      class { 'mq_install::internal::mq_stop':
        schedule  => $service_schedule,
        logoutput => $logoutput,
      }
      case $facts['kernel'] {
        'Linux': {
          #
          # When we do a downgrade (rollback) on Linux, we uninstall all the RPM's
          # that contantain the specified fixpack number
          #
          exec { "uninstall fixpack ${facts['mq_installed_fixpacks'][-1]}":
            command   => "rpm -qa | grep ${facts['mq_installed_fixpacks'][-1]} | xargs yum remove -y",
            path      => '/bin',
            schedule  => $service_schedule,
            logoutput => $logoutput,
          }
        }
        'SunOS': {
          #
          # When we do a downgrade (rollback) on SunOS, we uninstall the latest fixpack
          #
          exec { "uninstall fixpack ${facts['mq_installed_fixpacks'][-1]}":
            command   => "yes | pkgrm ${facts['mq_installed_fixpacks'][-1]}",
            path      => ['/usr/sbin', '/bin'],
            schedule  => $service_schedule,
            logoutput => $logoutput,
          }
        }
        default:  {
          fail "Kernel ${facts['kernel']} is not (yet) supported by the mq_install module."
        }
      }
    }
  }
}