zhmccli/_cmd_partition.py
# Copyright 2016,2019 IBM Corp. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Commands for partitions in DPM mode.
"""
from __future__ import absolute_import
from __future__ import print_function
import os
import io
import logging
import re
import click
from click_option_group import optgroup
import zhmcclient
from .zhmccli import cli, CONSOLE_LOGGER_NAME
from ._helper import print_properties, print_resources, abort_if_false, \
options_to_properties, original_options, COMMAND_OPTIONS_METAVAR, \
part_console, click_exception, storage_management_feature, \
add_options, LIST_OPTIONS, TABLE_FORMATS, hide_property, \
ASYNC_TIMEOUT_OPTIONS, API_VERSION_HMC_2_14_0, parse_adapter_names, \
parse_crypto_domains, domains_to_domain_config, \
domain_config_to_props_list, print_dicts
from ._cmd_cpc import find_cpc
from ._cmd_storagegroup import find_storagegroup
from ._cmd_certificates import find_certificate
from ._cmd_metrics import get_metric_values
from ._cmd_adapter import find_adapter
# Defaults for partition creation
DEFAULT_IFL_PROCESSORS = 1
DEFAULT_INITIAL_MEMORY_MB = 1024
DEFAULT_MAXIMUM_MEMORY_MB = 1024
DEFAULT_PROCESSOR_MODE = 'shared'
PARTITION_TYPES = ['ssc', 'linux', 'zvm']
DEFAULT_PARTITION_TYPE = 'linux'
DEFAULT_SSC_BOOT = 'installer'
DEFAULT_PROCESSING_WEIGHT = 100
MIN_PROCESSING_WEIGHT = 1
MAX_PROCESSING_WEIGHT = 999
MIN_BOOT_TIMEOUT = 60
MAX_BOOT_TIMEOUT = 600
def find_partition(cmd_ctx, client, cpc_name, partition_name):
"""
Find a partition by name and return its resource object.
"""
if client.version_info() >= API_VERSION_HMC_2_14_0:
# This approach is faster than going through the CPC.
# In addition, this approach supports users that do not have object
# access permission to the parent CPC of the LPAR.
partitions = client.consoles.console.list_permitted_partitions(
filter_args={'name': partition_name, 'cpc-name': cpc_name})
if len(partitions) != 1:
raise click_exception(
"Could not find partition '{p}' in CPC '{c}'.".
format(p=partition_name, c=cpc_name),
cmd_ctx.error_format)
partition = partitions[0]
else:
cpc = find_cpc(cmd_ctx, client, cpc_name)
# The CPC must be in DPM mode. We don't check that because it would
# cause a GET to the CPC resource that we otherwise don't need.
try:
partition = cpc.partitions.find(name=partition_name)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
return partition
@cli.group('partition', options_metavar=COMMAND_OPTIONS_METAVAR)
def partition_group():
"""
Command group for managing partitions (DPM mode only).
The commands in this group work only on CPCs that are in DPM mode.
The term 'partition' is used only for CPCs in DPM mode.
For CPCs in classic mode, the term 'LPAR' (logical partition) is used.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
@partition_group.command('list', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='[CPC]', required=False)
@click.option('--type', is_flag=True, required=False, hidden=True)
@add_options(LIST_OPTIONS)
@click.option('--ifl-usage', is_flag=True, required=False,
help='Show additional properties for IFL usage.')
@click.option('--cp-usage', is_flag=True, required=False,
help='Show additional properties for CP usage.')
@click.option('--memory-usage', is_flag=True, required=False,
help='Show additional properties for memory usage.')
@click.option('--help-usage', is_flag=True, required=False,
help='Help on the usage related options.')
@click.pass_obj
def partition_list(cmd_ctx, cpc, **options):
"""
List the permitted partitions in a CPC or in all managed CPCs.
Note that LPARs of CPCs in classic mode are not included.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_list(cmd_ctx, cpc, options))
@partition_group.command('show', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--all', is_flag=True, required=False,
help='Show all properties. Default: Hide some properties in '
'table output formats.')
@click.pass_obj
def partition_show(cmd_ctx, cpc, partition, **options):
"""
Show the details of a partition in a CPC.
The following properties are shown in addition to those returned by the HMC:
\b
- 'parent-name' - Name of the parent CPC.
- 'nic-names' - Names of the NICs referenced by 'nic-uris'
(index-correlated).
In table output formats, the following properties are hidden by default
but can be shown by using the --all option:
\b
- crypto-configuration
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_show(cmd_ctx, cpc, partition, options))
@partition_group.command('start', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@add_options(ASYNC_TIMEOUT_OPTIONS)
@click.pass_obj
def partition_start(cmd_ctx, cpc, partition, **options):
"""
Start a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_start(
cmd_ctx, cpc, partition, options))
@partition_group.command('stop', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@add_options(ASYNC_TIMEOUT_OPTIONS)
@click.pass_obj
def partition_stop(cmd_ctx, cpc, partition, **options):
"""
Stop a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_stop(
cmd_ctx, cpc, partition, options))
@partition_group.command('dump', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--volume', type=str, required=True,
help='The storage volume that contains the dump program. '
'For CPCs with the storage management feature (z14 and later): '
'A string of the form "SG/SV" where SG is the name '
'of the storage group resource attached to the partition and SV '
'is the name of the storage volume in that storage group, or of '
'the form "UUID" where UUID is the UUID of the storage volume '
'on the storage array (also shown in the HMC GUI). The storage '
'volume may be of type FCP or FICON. '
'For CPCs without the storage management feature (z13 and '
'earlier): A string of the form "HBA/WWPN/LUN", where HBA is the '
'name of the HBA resource in the partition and WWPN and LUN '
'identify the storage array and storage volume thereon. The '
'storage volume must be of type FCP.')
@click.option('--lba', type=str, required=False, default='0',
help='The logical block number of the anchor point for locating '
'the dump program on the storage volume. Default: 0')
@click.option('--configuration', type=int, required=False, default=0,
help='A selector that is passed to the dump program for '
'selecting the boot configuration to use. 0 means to use the '
'default boot configuration. Default: 0')
@click.option('--parameters', type=str, required=False, default='',
help='A parameter string that is passed to the dump program as '
'boot parameters. Default: empty string')
@click.option('--timeout', type=int, required=False, default=60,
help='The time in seconds that is waited before the load of the '
'dump program from a FICON storage volume is aborted. Only used '
'for CPCs with the storage management feature (z14 and later) '
'when loading from a FICON storage volume, and ignored '
'otherwise. Default: 60')
@add_options(ASYNC_TIMEOUT_OPTIONS)
@click.pass_obj
def partition_dump(cmd_ctx, cpc, partition, **options):
"""
Load and execute a standalone dump program from a volume.
This command loads a standalone dump program into a partition and begins
its execution. It does so in a special way that the existing contents of
the partition's memory are not overwritten so that the dump program can
dump those contents. The partition must be in one of the states "active",
"degraded", "paused", or "terminated".
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_dump(
cmd_ctx, cpc, partition, **options))
@partition_group.command('create', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@optgroup.group('General options')
@optgroup.option('--name', type=str, required=True,
help='The name of the new partition.')
@optgroup.option('--type', type=click.Choice(PARTITION_TYPES), required=False,
help='Defines the type of the partition. Default: {pd}'.
format(pd=DEFAULT_PARTITION_TYPE))
@optgroup.option('--description', type=str, required=False,
help='The description of the new partition.')
@optgroup.option('--short-name', type=str, required=False,
help='The short name (LPAR name) of the new partition.')
@optgroup.option('--partition-id', type=str, required=False,
help='The new partition ID (internal slot) of the partition. '
'Must be a non-conflicting hex number in the range 0 - 7F, '
'or "auto" for auto-generating it. Updating requires '
'partition to be stopped.')
@optgroup.option('--acceptable-status', type=str, required=False,
help='The set of acceptable operational status values, as a '
'comma-separated list. The empty string specifies an empty '
'list.')
@optgroup.option('--reserve-resources', type=bool, required=False,
help='Enables resource reservation, which causes all physical '
'resources backing the virtual resources configured for this '
'partition to be allocated and reserved, even when the '
'partition is in "stopped" state. Default: False')
@optgroup.group('CPU configuration')
@optgroup.option('--cp-processors', type=int, required=False,
help='The number of general purpose (CP) processors. '
'Default: No CP processors')
@optgroup.option('--ifl-processors', type=int, required=False,
help='The number of IFL processors. '
'Default: {d}, if no CP processors have been specified'.
format(d=DEFAULT_IFL_PROCESSORS))
@optgroup.option('--processor-mode', type=click.Choice(['dedicated', 'shared']),
required=False, default=DEFAULT_PROCESSOR_MODE,
help='The sharing mode for processors. '
'Default: {d}'.format(d=DEFAULT_PROCESSOR_MODE))
@optgroup.option('--processor-management-enabled', type=bool, required=False,
help='Indicates whether the processor management is enabled. '
'Default: false')
@optgroup.option('--initial-cp-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT),
required=False, default=DEFAULT_PROCESSING_WEIGHT,
help='Defines the initial processing weight of CP processors. '
'Default: {d}'.format(d=DEFAULT_PROCESSING_WEIGHT))
@optgroup.option('--initial-ifl-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT),
required=False, default=DEFAULT_PROCESSING_WEIGHT,
help='Defines the initial processing weight of IFL '
'processors. Default: {d}'.
format(d=DEFAULT_PROCESSING_WEIGHT))
@optgroup.option('--minimum-ifl-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT),
required=False, default=MIN_PROCESSING_WEIGHT,
help='Represents the minimum amount of IFL processor '
'resources allocated to the partition. '
'Default: {d}'.format(d=MIN_PROCESSING_WEIGHT))
@optgroup.option('--minimum-cp-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT),
required=False, default=MIN_PROCESSING_WEIGHT,
help='Represents the minimum amount of general purpose '
'processor resources allocated to the partition. '
'Default: {d}'.format(d=MIN_PROCESSING_WEIGHT))
@optgroup.option('--maximum-ifl-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT),
required=False, default=MAX_PROCESSING_WEIGHT,
help='Represents the maximum amount of IFL processor '
'resources allocated to the partition. '
'Default: {d}'.format(d=MAX_PROCESSING_WEIGHT))
@optgroup.option('--maximum-cp-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT),
required=False, default=MAX_PROCESSING_WEIGHT,
help='Represents the maximum amount of general purpose '
'processor resources allocated to the partition. '
'Default: {d}'.format(d=MAX_PROCESSING_WEIGHT))
@optgroup.option('--cp-absolute-capping', type=float, required=False,
help='Absolute CP processor capping. A numeric value prevents '
'the partition from using any more than the specified number '
'of physical processors. An empty string disables absolute '
'CP capping.')
@optgroup.option('--ifl-absolute-capping', type=float, required=False,
help='Absolute IFL processor capping. A numeric value prevents'
' the partition from using any more than the specified number '
'of physical processors. An empty string disables absolute '
'IFL capping.')
@optgroup.option('--cp-processing-weight-capped', type=bool, required=False,
help='Indicates whether the CP processor weight is capped. '
'If True, the processing weight is an upper limit. If False, '
'the processing weight is a target that can be exceeded if '
'excess CP processor resources are available.')
@optgroup.option('--ifl-processing-weight-capped', type=bool, required=False,
help='Indicates whether the IFL processor weight is capped. '
'If True, the processing weight is an upper limit. If False, '
'the processing weight is a target that can be exceeded if '
'excess IFL processor resources are available.')
@optgroup.group('Memory configuration')
@optgroup.option('--initial-memory', type=int, required=False,
default=DEFAULT_INITIAL_MEMORY_MB,
help='The initial amount of memory (in MiB) when the '
'partition is started. '
'Default: {d} MiB'.format(d=DEFAULT_INITIAL_MEMORY_MB))
@optgroup.option('--maximum-memory', type=int, required=False,
default=DEFAULT_MAXIMUM_MEMORY_MB,
help='The maximum amount of memory (in MiB) to which the '
'partition\'s memory allocation can be increased while the '
'partition is running. '
'Default: {d} MiB'.format(d=DEFAULT_MAXIMUM_MEMORY_MB))
@optgroup.group('Boot configuration')
@optgroup.option('--boot-timeout', required=False, metavar='INTEGER',
type=click.IntRange(MIN_BOOT_TIMEOUT, MAX_BOOT_TIMEOUT),
help='The time in seconds that is waited before an ongoing '
'boot is aborted. This is applicable for all boot sources. '
'Default: 60')
@optgroup.option('--boot-ftp-host', type=str, required=False,
help='Boot from an FTP server: The hostname or IP address of '
'the FTP server.')
@optgroup.option('--boot-ftp-username', type=str, required=False,
help='Boot from an FTP server: The user name on the FTP '
'server.')
@optgroup.option('--boot-ftp-password', type=str, required=False,
help='Boot from an FTP server: The password on the FTP '
'server.')
@optgroup.option('--boot-ftp-insfile', type=str, required=False,
help='Boot from an FTP server: The path to the INS-file on '
'the FTP server.')
@optgroup.option('--boot-media-file', type=str, required=False,
help='Boot from removable media on the HMC: The path to the '
'image file on the HMC.')
@optgroup.option('--boot-media-type', type=click.Choice(['usb', 'cdrom']),
required=False,
help='Boot from removable media on the HMC: The type of media.'
' Must be specified if --boot-media-file is specified.')
@optgroup.group('Special permission configuration')
@optgroup.option('--access-global-performance-data', type=bool, required=False,
help='Indicates if global performance data authorization '
'control is requested. Default: False')
@optgroup.option('--permit-cross-partition-commands', type=bool, required=False,
help='Indicates if cross partition commands authorization is'
'requested. Default: False')
@optgroup.option('--access-basic-counter-set', type=bool, required=False,
help='Indicates if basic counter set authorization control is '
'requested. Default: False')
@optgroup.option('--access-problem-state-counter-set', type=bool,
required=False,
help='Indicates if problem state counter set authorization '
'is requested. Default: False')
@optgroup.option('--access-crypto-activity-counter-set',
type=bool, required=False,
help='Indicates is crypto activity counter set authorization '
'control is requested. Default: False')
@optgroup.option('--access-extended-counter-set', type=bool, required=False,
help='Indicates if extended counter set authorization control '
'is requested. Default: False')
@optgroup.option('--access-basic-sampling', type=bool, required=False,
help='Indicates if basic CPU sampling authorization control '
'is requested. Default: False')
@optgroup.option('--access-diagnostic-sampling', type=bool, required=False,
help='Indicates if diagnostic sampling authorization control '
'is requested. Default: False')
@optgroup.option('--permit-des-key-import-functions', type=bool, required=False,
help='Enables the importing of DES keys for the partition. '
'Default: True')
@optgroup.option('--permit-aes-key-import-functions', type=bool, required=False,
help='Enables the importing of AES keys for the partition. '
'Default: True')
@optgroup.option('--permit-ecc-key-import-functions', type=bool, required=False,
help='Enables the importing of ECC keys for the partition. '
'Default: True')
@optgroup.group('SSC configuration (only applicable to SSC partitions)')
@optgroup.option('--ssc-host-name', type=str, required=False,
help='Secure Service Container host name. '
'Required for SSC partitions.')
@optgroup.option('--ssc-ipv4-gateway', type=str, required=False,
help='Default IPv4 Gateway to be used. '
'Empty string sets no IPv4 Gateway. '
'Default: No IPv4 Gateway')
@optgroup.option('--ssc-ipv6-gateway', type=str, required=False,
help='Default IPv6 Gateway to be used. '
'Empty string sets no IPv6 Gateway. '
'Only applicable to ssc type partitions.')
@optgroup.option('--ssc-dns-servers', type=str, required=False,
help='DNS IP addresses (comma-separated). '
'Empty string sets no DNS IP addresses. '
'Default: No DNS IP addresses')
@optgroup.option('--ssc-master-userid', type=str, required=False,
help='Secure Service Container master user ID. '
'Required for SSC partitions.')
@optgroup.option('--ssc-master-pw', type=str, required=False,
help='Secure Service Container master user password. '
'Required for SSC partitions.')
@click.pass_obj
def partition_create(cmd_ctx, cpc, **options):
"""
Create a partition in a CPC.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_create(cmd_ctx, cpc, options))
@partition_group.command('update', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@optgroup.group('General options')
@optgroup.option('--name', type=str, required=False,
help='The new name of the partition.')
@optgroup.option('--description', type=str, required=False,
help='The new description of the partition.')
@optgroup.option('--short-name', type=str, required=False,
help='The new short name (LPAR name) of the partition.')
@optgroup.option('--partition-id', type=str, required=False,
help='The new partition ID (internal slot) of the partition. '
'Must be a non-conflicting hex number in the range 0 - 7F, '
'or "auto" for auto-generating it. Updating requires '
'partition to be stopped.')
@optgroup.option('--acceptable-status', type=str, required=False,
help='The new set of acceptable operational status values, '
'as a comma-separated list. The empty string specifies an '
'empty list.')
@optgroup.option('--reserve-resources', type=bool, required=False,
help='Enables resource reservation, which causes all physical '
'resources backing the virtual resources configured for this '
'partition to be allocated and reserved, even when the '
'partition is in "stopped" state. Default: False')
@optgroup.group('CPU configuration')
@optgroup.option('--cp-processors', type=int, required=False,
help='The new number of general purpose (CP) processors.')
@optgroup.option('--ifl-processors', type=int, required=False,
help='The new number of IFL processors.')
@optgroup.option('--processor-mode', type=click.Choice(['dedicated', 'shared']),
required=False,
help='The new sharing mode for processors.')
@optgroup.option('--processor-management-enabled', type=bool, required=False,
help='Indicates whether the processor management is enabled.')
@optgroup.option('--initial-cp-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT), required=False,
help='Defines the initial processing weight of CP processors.')
@optgroup.option('--initial-ifl-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT), required=False,
help='Defines the initial processing weight of IFL '
'processors.')
@optgroup.option('--minimum-ifl-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT), required=False,
help='Represents the minimum amount of IFL processor '
'resources allocated to the partition.')
@optgroup.option('--minimum-cp-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT), required=False,
help='Represents the minimum amount of general purpose '
'processor resources allocated to the partition.')
@optgroup.option('--maximum-ifl-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT), required=False,
help='Represents the maximum amount of IFL processor '
'resources allocated to the partition.')
@optgroup.option('--maximum-cp-processing-weight',
type=click.IntRange(MIN_PROCESSING_WEIGHT,
MAX_PROCESSING_WEIGHT), required=False,
help='Represents the maximum amount of general purpose '
'processor resources allocated to the partition.')
@optgroup.option('--cp-absolute-capping', type=float, required=False,
help='Absolute CP processor capping. A numeric value prevents '
'the partition from using any more than the specified number '
'of physical processors. An empty string disables absolute '
'CP capping.')
@optgroup.option('--ifl-absolute-capping', type=float, required=False,
help='Absolute IFL processor capping. A numeric value '
'prevents the partition from using any more than the '
'specified number of physical processors. An empty string '
'disables absolute IFL capping.')
@optgroup.option('--cp-processing-weight-capped', type=bool, required=False,
help='Indicates whether the CP processor weight is capped. '
'If True, the processing weight is an upper limit. If False, '
'the processing weight is a target that can be exceeded if '
'excess CP processor resources are available.')
@optgroup.option('--ifl-processing-weight-capped', type=bool, required=False,
help='Indicates whether the IFL processor weight is capped. '
'If True, the processing weight is an upper limit. If False, '
'the processing weight is a target that can be exceeded if '
'excess IFL processor resources are available.')
@optgroup.group('Memory configuration')
@optgroup.option('--initial-memory', type=int, required=False,
help='The new initial amount of memory (in MiB) when the '
'partition is started.')
@optgroup.option('--maximum-memory', type=int, required=False,
help='The new maximum amount of memory (in MiB) to which the '
'partition\'s memory allocation can be increased while the '
'partition is running.')
@optgroup.group('Boot configuration')
@optgroup.option('--boot-storage-volume', type=str, required=False,
help='Boot from a storage volume. '
'For CPCs with the storage management feature (z14 and '
'later): A string of the form "SG/SV" where SG is the name of '
'the storage group attached to the partition and SV is the '
'name of the storage volume in that storage group, or of the '
'form "UUID" where UUID is the UUID of the storage volume on '
'the storage array (also shown in the HMC GUI). The storage '
'volume may be of type FCP or FICON. '
'For CPCs without the storage management feature (z13 and '
'earlier): A string of the form "HBA/WWPN/LUN", where HBA is '
'the name of the HBA to be used and WWPN and LUN identify the '
'storage array and storage volume thereon. The storage volume '
'must be of type FCP.')
@optgroup.option('--boot-storage-hba', type=str, required=False,
help='Boot from an FCP storage volume: The name of the HBA to '
'be used. '
'Deprecated, use --boot-storage-volume instead.')
@optgroup.option('--boot-storage-lun', type=str, required=False,
help='Boot from an FCP storage volume: The LUN of the storage '
'volume on the storage array. '
'Deprecated, use --boot-storage-volume instead.')
@optgroup.option('--boot-storage-wwpn', type=str, required=False,
help='Boot from an FCP storage volume: The WWPN of the '
'storage array that has the storage volume. '
'Deprecated, use --boot-storage-volume instead.')
@optgroup.option('--boot-network-nic', type=str, required=False,
help='Boot from a PXE server: The name of the NIC to be used.')
@optgroup.option('--boot-ftp-host', type=str, required=False,
help='Boot from an FTP server: The hostname or IP address of '
'the FTP server.')
@optgroup.option('--boot-ftp-username', type=str, required=False,
help='Boot from an FTP server: The user name on the FTP '
'server.')
@optgroup.option('--boot-ftp-password', type=str, required=False,
help='Boot from an FTP server: The password on the FTP '
'server.')
@optgroup.option('--boot-ftp-insfile', type=str, required=False,
help='Boot from an FTP server: The path to the INS-file on '
'the FTP server.')
@optgroup.option('--boot-media-file', type=str, required=False,
help='Boot from removable media on the HMC: The path to the '
'image file on the HMC.')
@optgroup.option('--boot-media-type', type=click.Choice(['usb', 'cdrom']),
required=False,
help='Boot from removable media on the HMC: The type of '
'media. Must be specified if --boot-media-file is specified.')
@optgroup.option('--boot-iso', is_flag=True, required=False,
help='Boot from an ISO image mounted to this partition. '
'The ISO image can be mounted using "zhmc partition '
'mountiso".')
@optgroup.option('--boot-iso-insfile', type=str, required=False,
help='Boot from an ISO image: The path to the INS-file in the '
'boot image.')
@optgroup.option('--boot-timeout', required=False, metavar='INTEGER',
type=click.IntRange(MIN_BOOT_TIMEOUT, MAX_BOOT_TIMEOUT),
help='The time in seconds that is waited before an ongoing '
'boot is aborted. This is applicable for all boot sources.')
@optgroup.option('--boot-ficon-loader-mode', required=False,
type=click.Choice(['ccw', 'list']),
help='The boot loader mode when booting from a FICON volume. '
'Must be "ccw" if secure-boot is false. If not specified, it '
'to is automatically set to "ccw" if secure-boot is false, '
'and "list" if secure-boot is true. If set to "list", the '
'FICON volume must have the correct format to work in '
'"list-directed" mode.')
@optgroup.option('--boot-record-location', type=str, required=False,
help='Location of the boot record on the FICON volume when '
'booting from a FICON volume, in the format '
'"cylinder.head.record" (each as a hex number). The empty '
'string will set the corresponding property to null, causing '
'the boot record location to be derived from the volume '
'label. After creation of the partition, the corresponding '
'property is null.')
@optgroup.option('--boot-record-lba', type=str, required=False,
help='Logical block number (as a hex number) of the anchor '
'point for locating the operating system when booting from '
'a SCSI volume. The way in which this parameter is used to '
'locate the operating system depends on the operating system '
'and its boot process. For Linux on IBM Z, for example, this '
'parameter specifies the block number of the master boot '
'record. After creation of the partition, the corresponding '
'property is 0.')
@optgroup.option('--boot-load-parameters', type=str, required=False,
help='Parameters that are passed unmodified to the operating '
'system boot process. The way in which these parameters are '
'used depends on the operating system, but in general, these '
'parameters are intended to be used to select an entry in '
'the boot menu or the boot loader. The length is restricted '
'to 8 characters, and valid characters are: 0-9, A-Z, @, $, '
'#, blank ( ), and period (.).'
'After creation of the partition, the corresponding property '
'is the empty string.')
@optgroup.option('--boot-os-specific-parameters', type=str, required=False,
help='Parameters that are passed unmodified to the operating '
'system boot process. The way in which these parameters are '
'used depends on the operating system, but in general, these '
'parameters are intended to specify boot-time configuration '
'settings. For Linux on IBM Z, for example, these parameters '
'specify kernel parameters. '
'After creation of the partition, the corresponding property '
'is the empty string.')
@optgroup.option('--boot-configuration', type=str, required=False,
# Properties: boot-configuration, boot-configuration-selector
help='Selects the boot configuration to use from among '
'multiple such boot configurations that have been defined '
'by the operating system to be loaded. Whether and how this '
'parameter is used to determine boot parameters depends on '
'the operating system and its boot process. For Linux on '
'IBM Z, for example, this parameter selects which of the '
'operating system\'s pre-configured boot configurations is to '
'be used, with the selected boot configuration in turn '
'specifying parameters such as the kernel to be loaded, the '
'kernel parameters to be used, or which disk is used as part '
'of the boot process. Must be a decimal number from 0 to 30, '
'or the string "auto". Using "auto" causes the boot loader '
'to automatically search for a boot configuration and to use '
'the first valid boot configuration defined in the operating '
'system. After creation of the partition, the corresponding '
'properties indicate to select boot configuration 0.')
@optgroup.option('--secure-boot', type=bool, required=False,
help='Check the software signature of what is booted against '
'what the distributor signed it with. '
'Requires z15 or later (recommended bundle levels on z15 are '
'at least H28 and S38), requires the boot volume to be '
'prepared for secure boot '
'(see https://linux.mainframe.blog/secure-boot/), requires '
'the partition to have type "linux" and boot-device '
'"storage-volume" with volume type "fcp" or "nvme". '
'Default: False')
@optgroup.group('Special permission configuration')
@optgroup.option('--access-global-performance-data', type=bool, required=False,
help='Indicates if global performance data authorization '
'control is requested. Default: False')
@optgroup.option('--permit-cross-partition-commands', type=bool, required=False,
help='Indicates if cross partition commands authorization is'
'requested. Default: False')
@optgroup.option('--access-basic-counter-set', type=bool, required=False,
help='Indicates if basic counter set authorization control is '
'requested. Default: False')
@optgroup.option('--access-problem-state-counter-set', type=bool,
required=False,
help='Indicates if problem state counter set authorization '
'is requested. Default: False')
@optgroup.option('--access-crypto-activity-counter-set',
type=bool, required=False,
help='Indicates is crypto activity counter set authorization '
'control is requested. Default: False')
@optgroup.option('--access-extended-counter-set', type=bool, required=False,
help='Indicates if extended counter set authorization control '
'is requested. Default: False')
@optgroup.option('--access-basic-sampling', type=bool, required=False,
help='Indicates if basic CPU sampling authorization control '
'is requested. Default: False')
@optgroup.option('--access-diagnostic-sampling', type=bool, required=False,
help='Indicates if diagnostic sampling authorization control '
'is requested. Default: False')
@optgroup.option('--permit-des-key-import-functions', type=bool, required=False,
help='Enables the importing of DES keys for the partition.')
@optgroup.option('--permit-aes-key-import-functions', type=bool, required=False,
help='Enables the importing of AES keys for the partition.')
@optgroup.option('--permit-ecc-key-import-functions', type=bool, required=False,
help='Enables the importing of ECC keys for the partition.')
@optgroup.group('SSC configuration (only applicable to SSC partitions)')
@optgroup.option('--ssc-host-name', type=str, required=False,
help='Secure Service Container host name.')
@optgroup.option('--ssc-boot-selection',
type=click.Choice(['installer']), required=False,
help='Set the boot mode of the Secure Service Container '
'to run the SSC Appliance Installer again upon next '
'partition start.')
@optgroup.option('--ssc-ipv4-gateway', type=str, required=False,
help='Default IPv4 Gateway to be used. '
'Empty string sets no IPv4 Gateway.')
@optgroup.option('--ssc-ipv6-gateway', type=str, required=False,
help='Default IPv6 Gateway to be used. '
'Empty string sets no IPv6 Gateway. '
'Only applicable to ssc type partitions.')
@optgroup.option('--ssc-dns-servers', type=str, required=False,
help='DNS IP addresses (comma-separated). '
'Empty string sets no DNS IP addresses.')
@optgroup.option('--ssc-master-userid', type=str, required=False,
help='Secure Service Container master user ID.')
@optgroup.option('--ssc-master-pw', type=str, required=False,
help='Secure Service Container master user password.')
@click.pass_obj
def partition_update(cmd_ctx, cpc, partition, **options):
"""
Update the properties of a partition.
Only the properties will be changed for which a corresponding option is
specified, so the default for all options is not to change properties.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_update(cmd_ctx, cpc, partition,
options))
@partition_group.command('delete', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('-y', '--yes', is_flag=True, callback=abort_if_false,
expose_value=False,
help='Skip prompt to confirm deletion of the partition.',
prompt='Are you sure you want to delete this partition ?')
@click.pass_obj
def partition_delete(cmd_ctx, cpc, partition):
"""
Delete a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_delete(cmd_ctx, cpc, partition))
@partition_group.command('console', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--refresh', is_flag=True, required=False,
help='Include refresh messages.')
@click.pass_obj
def partition_console(cmd_ctx, cpc, partition, **options):
"""
Establish an interactive session with the console of the operating system
running in a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_console(cmd_ctx, cpc, partition,
options))
@partition_group.command('mountiso', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--imagefile', type=str, required=True,
help='The file path of the ISO image file.')
@click.option('--imageinsfile', type=str, required=True,
help='The file path of the INS file (within the file system '
'of the ISO image file).')
@click.option('--boot', '-b', is_flag=True, required=False,
help='Set boot-device property to iso-image.')
@click.pass_obj
def partition_mount_iso(cmd_ctx, cpc, partition, **options):
"""
Mount an ISO image to a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_mount_iso(cmd_ctx, cpc,
partition, options))
@partition_group.command('unmountiso', options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.pass_obj
def partition_unmount_iso(cmd_ctx, cpc, partition):
"""
Unmount an ISO image from a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(lambda: cmd_partition_unmount_iso(cmd_ctx, cpc,
partition))
@partition_group.command('list-storagegroups',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.pass_obj
def partition_list_storagegroups(cmd_ctx, cpc, partition):
"""
List the storage groups attached to a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_list_storagegroups(cmd_ctx, cpc, partition))
@partition_group.command('attach-storagegroup',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--storagegroup', type=str, required=True,
help='The name of the storage group.')
@click.pass_obj
def partition_attach_storagegroup(cmd_ctx, cpc, partition, **options):
"""
Attach a storage group to a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_attach_storagegroup(cmd_ctx, cpc, partition,
options))
@partition_group.command('detach-storagegroup',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--storagegroup', type=str, required=True,
help='The name of the storage group.')
@click.pass_obj
def partition_detach_storagegroup(cmd_ctx, cpc, partition, **options):
"""
Detach a storage group from a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_detach_storagegroup(cmd_ctx, cpc, partition,
options))
@partition_group.command('assign-certificate',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--certificate', type=str, required=True,
help='The name of the certificate.')
@click.pass_obj
def partition_assign_certificate(cmd_ctx, cpc, partition, **options):
"""
Assign a certificate to a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_assign_certificate(cmd_ctx, cpc, partition,
options))
@partition_group.command('unassign-certificate',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--certificate', type=str, required=True,
help='The name of the certificate.')
@click.pass_obj
def partition_unassign_certificate(cmd_ctx, cpc, partition, **options):
"""
Unassign a certificate from a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_unassign_certificate(cmd_ctx, cpc, partition,
options))
@partition_group.command('show-crypto',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.pass_obj
def partition_show_crypto(cmd_ctx, cpc, partition):
"""
Show the crypto configuration of a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_show_crypto(cmd_ctx, cpc, partition))
@partition_group.command('add-crypto',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--adapters', '-a', type=str, required=False,
help='The crypto adapters to be added, as a '
'list in YAML Flow Collection style. The list items are the '
'adapter names. '
'Example: --adapters "[HSM1, HSM 2]"')
@click.option('--usage-domains', '-u', type=str, required=False,
help='The crypto domains to be added in control-usage mode, '
'as a list in YAML Flow Collection style. The list items are the '
'domain index numbers or ranges thereof (with \'-\'). '
'Example: --usage-domains "[0, 2-84]"')
@click.option('--control-domains', '-c', type=str, required=False,
help='The crypto domains to be added in control mode, as a '
'list in YAML Flow Collection style. The list items are the '
'domain index numbers or ranges thereof (with \'-\'). '
'Example: --control-domains "[0-1, 5]"')
@click.pass_obj
def partition_add_crypto(cmd_ctx, cpc, partition, **options):
"""
Add crypto domains and crypto adapters to the crypto configuration of a
partition.
This adds the new crypto domains for all crypto adapters, not just for the
added adapters.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_add_crypto(cmd_ctx, cpc, partition, options))
@partition_group.command('remove-crypto',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--adapters', '-a', type=str, required=False,
help='The crypto adapters to be removed, as a '
'list in YAML Flow Collection style. The list items are the '
'adapter names. '
'Example: --adapters "[HSM1, HSM 2]"')
@click.option('--domains', '-d', type=str, required=False,
help='The crypto domains to be removed, as a '
'list in YAML Flow Collection style. The list items are the '
'domain index numbers or ranges thereof (with \'-\'). '
'Example: --domains "[0, 2-84]"')
@click.pass_obj
def partition_remove_crypto(cmd_ctx, cpc, partition, **options):
"""
Remove crypto domains and crypto adapters from the crypto configuration of
a partition.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_remove_crypto(cmd_ctx, cpc, partition, options))
@partition_group.command('zeroize-crypto',
options_metavar=COMMAND_OPTIONS_METAVAR)
@click.argument('CPC', type=str, metavar='CPC')
@click.argument('PARTITION', type=str, metavar='PARTITION')
@click.option('--adapters', '-a', type=str, required=True,
help='The crypto adapters to be zeroized, as a '
'list in YAML Flow Collection style. The list items are the '
'adapter names. '
'Example: --adapters "[HSM1, HSM 2]"')
@click.option('--domains', '-d', type=str, required=True,
help='The crypto domains to be zeroized, as a '
'list in YAML Flow Collection style. The list items are the '
'domain index numbers or ranges thereof (with \'-\'). '
'Example: --domains "[0, 2-84]"')
@click.option('-y', '--yes', is_flag=True, callback=abort_if_false,
expose_value=False,
help='Skip prompt to confirm zeroizing the crypto domains.',
prompt='Are you sure you want to zeroize these crypto domains ?')
@click.pass_obj
def partition_zeroize_crypto(cmd_ctx, cpc, partition, **options):
"""
Zeroize crypto domains attached to a partition.
Zeroizing a crypto domain clears the cryptographic keys and non-compliance
mode settings in the domain.
This zeroizes all specified crypto domains on all specified crypto adapters.
At least one crypto domain and at least one crypto adapter must be
specified.
The crypto domains must be attached to the partition in "control-usage"
access mode.
In addition to the command-specific options shown in this help text, the
general options (see 'zhmc --help') can also be specified right after the
'zhmc' command name.
"""
cmd_ctx.execute_cmd(
lambda: cmd_partition_zeroize_crypto(cmd_ctx, cpc, partition, options))
def cmd_partition_list(cmd_ctx, cpc_name, options):
# pylint: disable=missing-function-docstring
if options['help_usage']:
help_lines = """
Help for usage related options of the partition list command:
--memory-usage option:
- 'reserve-resources' field: Boolean indicating whether the partition reserves
resources even when stopped.
- 'initial-memory' field: Memory allocated to the partition, in MiB.
--ifl-usage option:
- 'reserve-resources' field: Boolean indicating whether the partition reserves
resources even when stopped.
- 'processor-mode' field: 'shared' or 'dedicated' depending on the processor
sharing mode for the partition. This applies to all types of processors
(IFLs and CPs).
- 'ifls' field: Number of IFLs assigned to the partition. For dedicated
processor mode, each of these has the capacity of a physical processors.
For shared processor mode, these are shared processors each of which gets
a subset of the capacity of a physical processor.
This is the value of the 'ifl-processors' property of the partition.
- 'ifl-weight' field: IFL weight of the partition. This is a relative number
that is put in proportion to the IFL weights of other partitions.
Note that the IFL weight is applied at the partition level, not at the
IFL level.
This is the value of the 'initial-ifl-processing-weight' property of the
partition.
- 'ifl-capacity' field: IFL capacity assigned to the partition, in
units of physical IFLs.
The assigned IFL capacity takes into account the IFL weight of the
partition relative to the IFL weights of all other partitions that are
active and in shared processor mode.
This is a calculated value.
- 'processor-usage' field: The percentage of the processor (IFL and CP)
capacity of the partition that is actually used (=consumed).
This is the value of the 'processor-usage' metric of the partition.
- 'processors-used' field: Processor (IFL and CP) capacity currently consumed
by the partition, in units of physical processors.
This is a calculated value.
--cp-usage option: Same as --ifl-usage option, just with CPs instead of IFLs.
"""
cmd_ctx.spinner.stop()
click.echo(help_lines)
return
client = zhmcclient.Client(cmd_ctx.session)
if cpc_name:
# Make sure a non-existing CPC is raised as error
cpc = client.cpcs.find(name=cpc_name)
partitions = cpc.partitions.list()
elif client.version_info() >= API_VERSION_HMC_2_14_0:
# This approach is faster than looping through the CPCs.
# In addition, this approach supports users that do not have object
# access permission to the parent CPC of the returned partitions.
partitions = client.consoles.console.list_permitted_partitions()
else:
partitions = []
cpcs = client.cpcs.list()
for cpc in cpcs:
partitions.extend(cpc.partitions.list())
# The default exception handling is sufficient for the above.
if options['type']:
click.echo("The --type option is deprecated and type information "
"is now always shown.")
# Prepare the additions dict of dicts. It contains additional
# (=non-resource) property values by property name and by resource URI.
# Depending on options, some of them will not be populated.
additions = {}
additions['ifl-capacity'] = {}
additions['ifls'] = {}
additions['ifl-weight'] = {}
additions['cp-capacity'] = {}
additions['cps'] = {}
additions['cp-weight'] = {}
additions['processor-usage'] = {}
additions['processors-used'] = {}
additions['cpc'] = {}
show_list = [
'name',
'cpc',
]
if not options['names_only']:
show_list.extend([
'short-name',
'status',
'type',
'os-name',
'os-type',
'os-version',
'description',
])
if options['uri']:
show_list.extend([
'object-uri',
])
if options['memory_usage']:
try:
show_list.remove('description')
except ValueError:
pass
show_list.extend([
'reserve-resources',
'initial-memory',
])
if options['ifl_usage'] or options['cp_usage']:
for p in partitions:
p.pull_full_properties()
# Calculate effective IFLs and add it
total_ifls = {} # by CPC name
total_ifl_weight = {} # by CPC name
for p in partitions:
cpc = p.manager.parent
if p.properties['processor-mode'] == 'shared' and \
p.properties['status'] == 'active':
if cpc.name not in total_ifl_weight:
total_ifl_weight[cpc.name] = 0
total_ifls[cpc.name] = cpc.prop('processor-count-ifl')
total_ifl_weight[cpc.name] += \
p.properties['initial-ifl-processing-weight']
for p in partitions:
cpc = p.manager.parent
if p.properties['status'] != 'active':
ifls_eff = None
elif p.properties['processor-mode'] == 'shared':
ifl_weight = p.properties['initial-ifl-processing-weight']
ifls_eff = float(total_ifls[cpc.name]) * ifl_weight / \
total_ifl_weight[cpc.name]
else:
ifls_eff = float(p.properties['ifl-processors'])
additions['ifl-capacity'][p.uri] = ifls_eff
additions['ifls'][p.uri] = p.properties['ifl-processors']
additions['ifl-weight'][p.uri] = \
p.properties['initial-ifl-processing-weight']
# Calculate effective CPs and add it
total_cps = {} # by CPC name
total_cp_weight = {} # by CPC name
for p in partitions:
cpc = p.manager.parent
if p.properties['processor-mode'] == 'shared' and \
p.properties['status'] == 'active':
if cpc.name not in total_cp_weight:
total_cp_weight[cpc.name] = 0
total_cps[cpc.name] = \
cpc.prop('processor-count-general-purpose')
total_cp_weight[cpc.name] += \
p.properties['initial-cp-processing-weight']
for p in partitions:
cpc = p.manager.parent
if p.properties['status'] != 'active':
cps_eff = None
elif p.properties['processor-mode'] == 'shared':
cp_weight = p.properties['initial-cp-processing-weight']
cps_eff = float(total_cps[cpc.name]) * cp_weight / \
total_cp_weight[cpc.name]
else:
cps_eff = float(p.properties['cp-processors'])
additions['cp-capacity'][p.uri] = cps_eff
additions['cps'][p.uri] = p.properties['cp-processors']
additions['cp-weight'][p.uri] = \
p.properties['initial-cp-processing-weight']
# Get processor-usage metrics and add it
metric_group = 'partition-usage'
resource_filter = []
if cpc_name:
resource_filter.append(('cpc', cpc_name))
mov_list, _ = get_metric_values(
client, metric_group, resource_filter)
partition_metrics = {}
for mov in mov_list:
assert isinstance(mov.resource, zhmcclient.Partition)
p_name = mov.resource.name
partition_metrics[p_name] = mov.metrics
for p in partitions:
# Note: Partitions that are stopped have no metrics value for
# partition-usage.
p_metrics = partition_metrics.get(p.name, None)
if p_metrics:
usage = p_metrics['processor-usage']
# Independent of sharing mode:
procs_eff = (additions['ifl-capacity'][p.uri] or 0) + \
(additions['cp-capacity'][p.uri] or 0)
used = float(usage) / 100 * procs_eff
else:
usage = None
used = None
additions['processor-usage'][p.uri] = usage
additions['processors-used'][p.uri] = used
try:
show_list.remove('description')
except ValueError:
pass
show_list.append('reserve-resources')
show_list.append('processor-mode')
if options['ifl_usage']:
show_list.append('ifls')
show_list.append('ifl-weight')
show_list.append('ifl-capacity')
if options['cp_usage']:
show_list.append('cps')
show_list.append('cp-weight')
show_list.append('cp-capacity')
show_list.append('processor-usage')
show_list.append('processors-used')
for p in partitions:
cpc = p.manager.parent
additions['cpc'][p.uri] = cpc.name
try:
print_resources(cmd_ctx, partitions, cmd_ctx.output_format, show_list,
additions, all=options['all'])
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
def cmd_partition_show(cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
try:
partition.pull_full_properties()
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
properties = dict(partition.properties)
# Add artificial property 'parent-name'
properties['parent-name'] = cpc_name
# Hide some long or deeply nested properties in table output formats.
if not options['all'] and cmd_ctx.output_format in TABLE_FORMATS:
hide_property(properties, 'crypto-configuration')
# Add artificial property 'nic-names'
nic_names = []
for nic_uri in partition.properties['nic-uris']:
nic_props = client.session.get(nic_uri)
nic_names.append(nic_props['name'])
properties['nic-names'] = nic_names
print_properties(cmd_ctx, properties, cmd_ctx.output_format)
def cmd_partition_start(cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
try:
partition.start(wait_for_completion=True,
operation_timeout=options['operation_timeout'])
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Partition '{p}' has been started.".format(p=partition_name))
def cmd_partition_stop(cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
try:
partition.stop(wait_for_completion=True,
operation_timeout=options['operation_timeout'])
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Partition '{p}' has been stopped.".format(p=partition_name))
def cmd_partition_create(cmd_ctx, cpc_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
cpc = find_cpc(cmd_ctx, client, cpc_name)
# The following options are handled specifically in this function (as
# opposed to be handled generically in options_to_properties()):
# The options for booting from an FTP server.
# They need to be specified together, all of them are required.
boot_ftp_option_names = (
'boot-ftp-host',
'boot-ftp-username',
'boot-ftp-password',
'boot-ftp-insfile',
)
# The option for booting from an HMC media file.
boot_media_option_names = (
'boot-media-file',
'boot-media-type',
)
# Specially handled options
special_option_names = (
'partition-id',
'acceptable-status',
'ssc-dns-servers',
'ssc-ipv4-gateway',
'ssc-ipv6-gateway',
'cp-absolute-capping',
'ifl-absolute-capping',
)
# Options handled in this function
special_opt_names = boot_ftp_option_names + boot_media_option_names + \
special_option_names
name_map = dict((opt, None) for opt in special_opt_names)
org_options = original_options(options)
properties = options_to_properties(org_options, name_map)
# Used and missing options handled in this function
used_boot_ftp_opts = [
'--' + name for name in boot_ftp_option_names
if org_options[name] is not None]
missing_boot_ftp_opts = [
'--' + name for name in boot_ftp_option_names
if org_options[name] is None]
used_boot_media_opts = [
'--' + name for name in boot_media_option_names
if org_options[name] is not None]
used_boot_opts = used_boot_ftp_opts + used_boot_media_opts
num_boot_devices = bool(used_boot_ftp_opts) + bool(used_boot_media_opts)
if num_boot_devices > 1:
raise click_exception(
"Boot from multiple devices specified: {opts}".
format(opts=', '.join(used_boot_opts)),
cmd_ctx.error_format)
if used_boot_ftp_opts:
if missing_boot_ftp_opts:
raise click_exception(
"Boot from FTP server specified, but misses the following "
"options: {opts}".
format(opts=', '.join(missing_boot_ftp_opts)),
cmd_ctx.error_format)
properties['boot-device'] = 'ftp'
properties['boot-ftp-host'] = org_options['boot-ftp-host']
properties['boot-ftp-username'] = org_options['boot-ftp-username']
properties['boot-ftp-password'] = org_options['boot-ftp-password']
properties['boot-ftp-insfile'] = org_options['boot-ftp-insfile']
elif used_boot_media_opts:
properties['boot-device'] = 'removable-media'
properties['boot-removable-media'] = org_options['boot-media-file']
properties['boot-removable-media-type'] = org_options['boot-media-type']
else:
# boot-device="none" is the default
pass
# Default for the number of processors
if 'ifl-processors' not in properties and \
'cp-processors' not in properties:
properties['ifl-processors'] = DEFAULT_IFL_PROCESSORS
# Specially handled options
if org_options['partition-id'] == "auto":
properties['autogenerate-partition-id'] = True
elif org_options['partition-id'] is not None:
partition_id = "{:02X}".format(org_options['partition-id'])
properties['partition-id'] = partition_id
properties['autogenerate-partition-id'] = False
if org_options['acceptable-status'] is not None:
status_list = org_options['acceptable-status'].split(',')
status_list = [item for item in status_list if item]
properties['acceptable-status'] = status_list
if org_options['ssc-dns-servers'] == '':
properties['ssc-dns-servers'] = []
elif org_options['ssc-dns-servers'] is not None:
properties['ssc-dns-servers'] = \
org_options['ssc-dns-servers'].split(',')
if org_options['ssc-ipv4-gateway'] == '':
properties['ssc-ipv4-gateway'] = None
if org_options['ssc-ipv6-gateway'] == '':
properties['ssc-ipv6-gateway'] = None
if org_options['cp-absolute-capping'] == '':
properties['cp-absolute-processor-capping'] = False
elif org_options['cp-absolute-capping'] is not None:
properties['cp-absolute-processor-capping'] = True
properties['cp-absolute-processor-capping-value'] = \
org_options['cp-absolute-capping']
if org_options['ifl-absolute-capping'] == '':
properties['ifl-absolute-processor-capping'] = False
elif org_options['ifl-absolute-capping'] is not None:
properties['ifl-absolute-processor-capping'] = True
properties['ifl-absolute-processor-capping-value'] = \
org_options['ifl-absolute-capping']
try:
new_partition = cpc.partitions.create(properties)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("New partition '{p}' has been created.".
format(p=new_partition.properties['name']))
def cmd_partition_update(cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
# The following options are handled specifically in this function (as
# opposed to be handled generically in options_to_properties()):
# The option for booting from a storage volume.
# For consistency, a list is used even though it is a single option.
boot_storage_option_names = (
'boot-storage-volume',
)
# The deprecated options for booting from an FCP storage volume.
# They need to be specified together, all of them are required.
old_boot_storage_option_names = (
'boot-storage-hba',
'boot-storage-lun',
'boot-storage-wwpn',
)
# The option for booting from a PXE server.
# For consistency, a list is used even though it is a single option.
boot_network_option_names = (
'boot-network-nic',
)
# The options for booting from an FTP server.
# They need to be specified together, all of them are required.
boot_ftp_option_names = (
'boot-ftp-host',
'boot-ftp-username',
'boot-ftp-password',
'boot-ftp-insfile',
)
# The option for booting from an HMC media file.
# For consistency, a list is used even though it is a single option.
boot_media_option_names = (
'boot-media-file',
)
# The option for booting from an HMC ISO image.
# For consistency, a list is used even though it is a single option.
boot_iso_option_names = (
'boot-iso',
)
# Specially handled options
special_option_names = (
'partition-id',
'acceptable-status',
'ssc-dns-servers',
'ssc-ipv4-gateway',
'ssc-ipv6-gateway',
'cp-absolute-capping',
'ifl-absolute-capping',
'boot-ficon-loader-mode',
'boot-record-lba',
'boot-record-location',
'boot-configuration',
)
# Addiional name mapping
additional_name_mapping = {
# option name: HMC property name
'boot-iso-insfile': 'boot-iso-ins-file',
}
# Options handled in this function
special_opt_names = \
boot_storage_option_names + old_boot_storage_option_names + \
boot_network_option_names + boot_ftp_option_names + \
boot_media_option_names + boot_iso_option_names + \
special_option_names
name_map = dict((opt, None) for opt in special_opt_names)
name_map.update(additional_name_mapping)
org_options = original_options(options)
properties = options_to_properties(org_options, name_map)
# Used and missing options handled in this function
used_boot_storage_opts = [
'--' + name for name in boot_storage_option_names
if org_options[name] is not None]
used_old_boot_storage_opts = [
'--' + name for name in old_boot_storage_option_names
if org_options[name] is not None]
missing_old_boot_storage_opts = [
'--' + name for name in old_boot_storage_option_names
if org_options[name] is None]
used_boot_network_opts = [
'--' + name for name in boot_network_option_names
if org_options[name] is not None]
used_boot_ftp_opts = [
'--' + name for name in boot_ftp_option_names
if org_options[name] is not None]
missing_boot_ftp_opts = [
'--' + name for name in boot_ftp_option_names
if org_options[name] is None]
used_boot_media_opts = [
'--' + name for name in boot_media_option_names
if org_options[name] is not None]
used_boot_iso_opts = [
'--' + name for name in boot_iso_option_names
if org_options[name]] # is_flag options default to False
if used_boot_storage_opts and used_old_boot_storage_opts:
raise click_exception(
"Boot from storage volume specified using both "
"--boot-storage-volume and the deprecated options "
"--boot-storage-hba/lun/wwpn",
cmd_ctx.error_format)
used_boot_opts = \
used_boot_storage_opts + used_old_boot_storage_opts + \
used_boot_network_opts + used_boot_ftp_opts + \
used_boot_media_opts + used_boot_iso_opts
num_boot_devices = \
bool(used_boot_storage_opts + used_old_boot_storage_opts) + \
bool(used_boot_network_opts) + bool(used_boot_ftp_opts) + \
bool(used_boot_media_opts) + bool(used_boot_iso_opts)
if num_boot_devices > 1:
raise click_exception(
"Boot from multiple devices specified: {opts}".
format(opts=', '.join(used_boot_opts)),
cmd_ctx.error_format)
if used_boot_storage_opts:
sv_name = org_options['boot-storage-volume']
if storage_management_feature(partition):
storage_volume = parse_volume_with_sm(
sv_name, partition, "--boot-storage-volume option",
cmd_ctx.error_format)
properties['boot-device'] = 'storage-volume'
properties['boot-storage-volume'] = storage_volume.uri
else:
hba, wwpn, lun = parse_volume_without_sm(
sv_name, partition, "--boot-storage-volume option",
cmd_ctx.error_format)
properties['boot-device'] = 'storage-adapter'
properties['boot-storage-device'] = hba.uri
properties['boot-world-wide-port-name'] = wwpn
properties['boot-logical-unit-number'] = lun
elif used_old_boot_storage_opts:
if storage_management_feature(partition):
raise click_exception(
"The deprecated options --boot-storage-hba/lun/wwpn can be "
"used only with CPCs without the storage management feature "
"(z13 and earlier)",
cmd_ctx.error_format)
if missing_old_boot_storage_opts:
raise click_exception(
"Boot from storage volume specified using the deprecated "
"options --boot-storage-hba/lun/wwpn, but misses the "
"following options: {opts}".
format(opts=', '.join(missing_old_boot_storage_opts)),
cmd_ctx.error_format)
click.echo("Deprecated: The options --boot-storage-hba/lun/wwpn are "
"deprecated. Use the --boot-storage-volume option instead")
properties['boot-device'] = 'storage-adapter'
properties['boot-storage-device'] = hba.uri
properties['boot-world-wide-port-name'] = \
org_options['boot-storage-wwpn']
properties['boot-logical-unit-number'] = \
org_options['boot-storage-lun']
elif used_boot_network_opts:
nic_name = org_options['boot-network-nic']
try:
nic = partition.nics.find(name=nic_name)
except zhmcclient.NotFound:
raise click_exception("Could not find NIC '{n}' in partition '{p}' "
"in CPC '{c}'.".
format(n=nic_name, p=partition_name,
c=cpc_name),
cmd_ctx.error_format)
properties['boot-device'] = 'network-adapter'
properties['boot-network-device'] = nic.uri
elif used_boot_ftp_opts:
if missing_boot_ftp_opts:
raise click_exception("Boot from FTP server specified, but misses "
"the following options: {o}".
format(o=', '.join(missing_boot_ftp_opts)),
cmd_ctx.error_format)
properties['boot-device'] = 'ftp'
properties['boot-ftp-host'] = org_options['boot-ftp-host']
properties['boot-ftp-username'] = org_options['boot-ftp-username']
properties['boot-ftp-password'] = org_options['boot-ftp-password']
properties['boot-ftp-insfile'] = org_options['boot-ftp-insfile']
elif used_boot_media_opts:
properties['boot-device'] = 'removable-media'
properties['boot-removable-media'] = org_options['boot-media-file']
elif used_boot_iso_opts:
properties['boot-device'] = 'iso-image'
# Note: 'boot-iso-image-name' is read-only and is changed by using
# the Mount/Unmount ISO operations.
# Note: 'boot-iso-ins-file' is writeable, for using a different
# INS file than the one specified in Mount ISO. This is not
# currently supported by zhmccli.
else:
# boot-device="none" is the default
pass
# Specially handled options
if org_options['partition-id'] == "auto":
properties['autogenerate-partition-id'] = True
elif org_options['partition-id'] is not None:
partition_id = "{:02X}".format(org_options['partition-id'])
properties['partition-id'] = partition_id
properties['autogenerate-partition-id'] = False
if org_options['acceptable-status'] is not None:
status_list = org_options['acceptable-status'].split(',')
status_list = [item for item in status_list if item]
properties['acceptable-status'] = status_list
if org_options['ssc-dns-servers'] == '':
properties['ssc-dns-servers'] = []
elif org_options['ssc-dns-servers'] is not None:
properties['ssc-dns-servers'] = \
org_options['ssc-dns-servers'].split(',')
if org_options['ssc-ipv4-gateway'] == '':
properties['ssc-ipv4-gateway'] = None
if org_options['ssc-ipv6-gateway'] == '':
properties['ssc-ipv6-gateway'] = None
if org_options['cp-absolute-capping'] == '':
properties['cp-absolute-processor-capping'] = False
elif org_options['cp-absolute-capping'] is not None:
properties['cp-absolute-processor-capping'] = True
properties['cp-absolute-processor-capping-value'] = \
org_options['cp-absolute-capping']
if org_options['ifl-absolute-capping'] == '':
properties['ifl-absolute-processor-capping'] = False
elif org_options['ifl-absolute-capping'] is not None:
properties['ifl-absolute-processor-capping'] = True
properties['ifl-absolute-processor-capping-value'] = \
org_options['ifl-absolute-capping']
if org_options['boot-ficon-loader-mode'] == 'ccw':
properties['boot-loader-mode'] = 'channel-command-word'
elif org_options['boot-ficon-loader-mode'] == 'list':
properties['boot-loader-mode'] = 'list-directed'
if org_options['boot-record-lba'] == '':
properties['boot-record-lba'] = None
elif org_options['boot-record-lba'] is not None:
properties['boot-record-lba'] = org_options['boot-record-lba']
if org_options['boot-record-location'] == '':
properties['boot-record-location'] = None
elif org_options['boot-record-location'] is not None:
value = org_options['boot-record-location']
m = re.match(r'([0-9A-F]+)\.([0-9A-F]+)\.([0-9A-F]+)$', value, re.I)
if not m:
raise click_exception(
"Invalid format specified for --boot-record-location "
"option: {v}.".format(v=value),
cmd_ctx.error_format)
cylinder, head, record = m.groups()
properties['boot-record-location'] = {
'cylinder': cylinder,
'head': head,
'record': record,
}
if org_options['boot-configuration'] == 'auto':
properties['boot-configuration'] = 'automatic'
elif org_options['boot-configuration'] is not None:
try:
value = int(org_options['boot-configuration'])
except ValueError:
raise click_exception(
"Invalid decimal value specified for --boot-configuration "
"option: {v}.".format(v=value),
cmd_ctx.error_format)
properties['boot-configuration'] = 'selector'
properties['boot-configuration-selector'] = value
if not properties:
cmd_ctx.spinner.stop()
click.echo("No properties specified for updating partition '{p}'.".
format(p=partition_name))
return
try:
partition.update_properties(properties)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
if 'name' in properties and properties['name'] != partition_name:
click.echo("Partition '{p}' has been renamed to '{pn}' and was "
"updated.".
format(p=partition_name, pn=properties['name']))
else:
click.echo("Partition '{p}' has been updated.".format(p=partition_name))
def cmd_partition_delete(cmd_ctx, cpc_name, partition_name):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
try:
partition.delete()
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Partition '{p}' has been deleted.".format(p=partition_name))
def cmd_partition_console(cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
logger = logging.getLogger(CONSOLE_LOGGER_NAME)
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
refresh = options['refresh']
cmd_ctx.spinner.stop()
try:
part_console(cmd_ctx.session, partition, refresh, logger)
except zhmcclient.Error as exc:
raise click.ClickException(
"{exc}: {msg}".format(exc=exc.__class__.__name__, msg=exc))
def cmd_partition_dump(cmd_ctx, cpc_name, partition_name, **options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
if storage_management_feature(partition):
partition_dump_with_sm(cmd_ctx, partition, **options)
else:
partition_dump_without_sm(cmd_ctx, partition, **options)
cmd_ctx.spinner.stop()
click.echo('Dump of Partition %s is complete.' % partition.name)
def partition_dump_with_sm(cmd_ctx, partition, **options):
"""Dump partition on CPCs that have the storage mgmt feature enabled"""
# Maps zhmc command options to fields of the dump-program-info parameter
# within the Start Dump Program parameters
dpi_name_map = {
'configuration': 'dump-configuration-selector',
'parameters': 'dump-os-specific-parameters',
'lba': 'dump-record-lba',
'volume': None, # Handled in this function
'timeout': None, # Handled in this function
}
org_options = original_options(options)
dpi_parms = options_to_properties(org_options, dpi_name_map)
volume_opt = options['volume'] # It is required
timeout = options['timeout'] # It is optional but has a default
storage_volume = parse_volume_with_sm(
volume_opt, partition, "--volume option", cmd_ctx.error_format)
# Set the remaining dump-program-info parameters
dpi_parms['storage-volume-uri'] = storage_volume.uri
if storage_volume.manager.parent.prop('type') == 'fc':
# HMC rejects timeout on non-FICON volumes with 400,14.
dpi_parms['timeout'] = timeout
parameters = {
'dump-program-info': dpi_parms,
'dump-program-type': 'storage',
}
try:
partition.start_dump_program(
parameters=parameters, wait_for_completion=True,
operation_timeout=options['operation_timeout'])
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
def partition_dump_without_sm(cmd_ctx, partition, **options):
"""Dump partition on CPCs that have the storage mgmt feature disabled"""
# Maps zhmc command options to Dump Partition parameters
name_map = {
'configuration': 'dump-configuration-selector',
'parameters': 'dump-os-specific-parameters',
'lba': 'dump-record-lba',
'volume': None, # Handled in this function
'timeout': None, # Ignored
}
org_options = original_options(options)
parameters = options_to_properties(org_options, name_map)
volume_opt = options['volume'] # It is required
hba, wwpn, lun = parse_volume_without_sm(
volume_opt, partition, "--volume option", cmd_ctx.error_format)
# Set the remaining Dump Partition parameters
parameters['dump-load-hba-uri'] = hba.uri
parameters['dump-world-wide-port-name'] = wwpn
parameters['dump-logical-unit-number'] = lun
try:
partition.dump_partition(
parameters=parameters, wait_for_completion=True,
operation_timeout=options['operation_timeout'])
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
def cmd_partition_mount_iso(cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
image_file = options['imagefile']
_, image_name = os.path.split(image_file)
with io.open(image_file, 'rb') as image_fp:
partition.mount_iso_image(image_fp, image_name, options['imageinsfile'])
if options['boot']:
partition.update_properties({'boot-device': 'iso-image'})
cmd_ctx.spinner.stop()
click.echo("ISO image {i} has been mounted to partition '{p}'.".
format(i=image_name, p=partition.name))
def cmd_partition_unmount_iso(cmd_ctx, cpc_name, partition_name):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
partition.pull_full_properties()
image_name = partition.get_property('boot-iso-image-name')
if image_name:
boot_device = partition.get_property('boot-device')
if boot_device == 'iso-image':
partition.update_properties({'boot-device': 'none'})
partition.unmount_iso_image()
cmd_ctx.spinner.stop()
click.echo("ISO image {i} has been unmounted from partition '{p}'.".
format(i=image_name, p=partition.name))
else:
cmd_ctx.spinner.stop()
click.echo("No ISO image is mounted to partition '{p}'.".
format(p=partition.name))
def cmd_partition_list_storagegroups(cmd_ctx, cpc_name, partition_name):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
try:
stogrps = partition.list_attached_storage_groups()
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
show_list = [
'name',
'type',
'shared',
'fulfillment-state',
]
try:
print_resources(cmd_ctx, stogrps, cmd_ctx.output_format, show_list)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
def cmd_partition_attach_storagegroup(
cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
stogrp_name = options['storagegroup']
stogrp = find_storagegroup(cmd_ctx, client, stogrp_name)
try:
partition.attach_storage_group(stogrp)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Storage group '{sg}' was attached to partition '{p}'.".
format(sg=stogrp_name, p=partition.name))
def cmd_partition_detach_storagegroup(
cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
stogrp_name = options['storagegroup']
stogrp = find_storagegroup(cmd_ctx, client, stogrp_name)
try:
partition.detach_storage_group(stogrp)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Storage group '{sg}' was detached from partition '{p}'.".
format(sg=stogrp_name, p=partition.name))
def cmd_partition_assign_certificate(
cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
cert_name = options['certificate']
cert = find_certificate(cmd_ctx, client, cert_name)
try:
partition.assign_certificate(cert)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Certificate '{cert}' was assigned to partition '{p}'.".
format(cert=cert_name, p=partition.name))
def cmd_partition_unassign_certificate(
cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
cert_name = options['certificate']
cert = find_certificate(cmd_ctx, client, cert_name)
try:
partition.unassign_certificate(cert)
except zhmcclient.Error as exc:
raise click_exception(exc, cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Certificate '{cert}' was unassigned from partition '{p}'.".
format(cert=cert_name, p=partition.name))
def cmd_partition_show_crypto(cmd_ctx, cpc_name, partition_name):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
cpc = find_cpc(cmd_ctx, client, cpc_name)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
partition.pull_properties('crypto-configuration')
config = partition.properties['crypto-configuration']
if config:
adapter_uris = config['crypto-adapter-uris']
domain_configs = config['crypto-domain-configurations']
adapters = [a for a in cpc.adapters.list() if a.uri in adapter_uris]
props_list = domain_config_to_props_list(
adapters, 'adapter', domain_configs)
else:
props_list = []
# define order of columns in output table
show_list = [
'adapter',
'domains',
'access-mode',
]
print_dicts(cmd_ctx, props_list, cmd_ctx.output_format,
show_list=show_list)
def cmd_partition_add_crypto(cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
adapters_option = options['adapters']
usage_domains_option = options['usage_domains']
control_domains_option = options['control_domains']
adapters = []
if adapters_option:
adapter_names = parse_adapter_names(
cmd_ctx, '--adapters', adapters_option)
for adapter_name in adapter_names:
adapter = find_adapter(cmd_ctx, client, cpc_name, adapter_name)
adapters.append(adapter)
else:
adapter_names = []
if usage_domains_option:
usage_domains = parse_crypto_domains(
cmd_ctx, '--usage-domains', usage_domains_option)
else:
usage_domains = []
if control_domains_option:
control_domains = parse_crypto_domains(
cmd_ctx, '--control-domains', control_domains_option)
else:
control_domains = []
domain_config = domains_to_domain_config(usage_domains, control_domains)
try:
partition.increase_crypto_config(adapters, domain_config)
except zhmcclient.Error as exc:
raise click_exception(
"Error attaching crypto usage domains {ud!r} and control domains "
"{cd!r} and adapters {a!r} to partition {p!r}: {exc}".
format(ud=usage_domains_option, cd=control_domains_option,
a=adapter_names, p=partition.name, exc=exc),
cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Attached crypto usage domains {ud!r} and control domains "
"{cd!r} and adapters {a!r} to partition {p!r}.".
format(ud=usage_domains_option, cd=control_domains_option,
a=adapter_names, p=partition.name))
def cmd_partition_remove_crypto(
cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
adapters_option = options['adapters']
domains_option = options['domains']
adapters = []
if adapters_option:
adapter_names = parse_adapter_names(
cmd_ctx, '--adapters', adapters_option)
for adapter_name in adapter_names:
adapter = find_adapter(cmd_ctx, client, cpc_name, adapter_name)
adapters.append(adapter)
else:
adapter_names = []
if domains_option:
domains = parse_crypto_domains(cmd_ctx, '--domains', domains_option)
else:
domains = []
try:
partition.decrease_crypto_config(adapters, domains)
except zhmcclient.Error as exc:
raise click_exception(
"Error detaching crypto domains {d!r} and adapters {a!r} from "
"partition {p!r}: {exc}".
format(d=domains_option, a=adapter_names, p=partition.name,
exc=exc),
cmd_ctx.error_format)
cmd_ctx.spinner.stop()
click.echo("Detached crypto domains {d!r} and adapters {a!r} from "
"partition {p!r}.".
format(d=domains_option, a=adapter_names, p=partition.name))
def cmd_partition_zeroize_crypto(
cmd_ctx, cpc_name, partition_name, options):
# pylint: disable=missing-function-docstring
client = zhmcclient.Client(cmd_ctx.session)
partition = find_partition(cmd_ctx, client, cpc_name, partition_name)
adapters_option = options['adapters'] # required
domains_option = options['domains'] # required
adapters = []
adapter_names = parse_adapter_names(cmd_ctx, '--adapters', adapters_option)
for adapter_name in adapter_names:
adapter = find_adapter(cmd_ctx, client, cpc_name, adapter_name)
adapters.append(adapter)
domains = parse_crypto_domains(cmd_ctx, '--domains', domains_option)
errors = 0
for adapter in adapters:
for domain in domains:
try:
partition.zeroize_crypto_domain(adapter, domain)
except zhmcclient.Error as exc:
errors += 1
cmd_ctx.spinner.stop()
click.echo(
"Error zeroizing crypto domain {d!r} on adapter {a!r}: "
"{exc} - continuing with next domain/adapter".
format(d=domain, a=adapter.name, exc=exc))
cmd_ctx.spinner.stop()
if errors:
raise click_exception(
"Zeroized crypto domains {d!r} on adapters {a!r} except for the "
"errors shown above.".format(d=domains_option, a=adapter_names),
cmd_ctx.error_format)
click.echo("Zeroized crypto domains {d!r} on adapters {a!r}.".
format(d=domains_option, a=adapter_names))
# pylint: disable=inconsistent-return-statements
def parse_volume_with_sm(volume_specifier, partition, where, error_format):
"""
Parse a volume specifier for a CPC with the storage management feature
(i.e. z14 or later) and return its StorageVolume resource object.
The partition that has the storage group of the volume attached, must be
known.
Parameters:
volume_specifier (string): The volume specifier, in one of these forms:
* "SG/SV", where SG is the name of the storage group resource
attached to the partition and SV is the name of the storage volume
in that storage group.
* "UUID", where UUID is the UUID of the storage volume on the storage
array (also shown in the HMC GUI).
partition (Partition): The partition that has the storage group attached
that contains the specified volume.
cpc_name (string): Name of the CPC containinng the partition (only used
for messages).
where (string): Text stating where the volue has been specified, e.g.
"--volume option" (only used for messages).
error_format (string):
The error format (see ``--error-format`` general option, only used for
messages).
Returns:
zhmcclient.StorageVolume: The storage volume resource (of type FCP or
FICON.)
"""
cpc_name = partition.manager.parent.name
volume_parts = volume_specifier.split('/')
if len(volume_parts) == 1: # format: UUID
uuid = volume_parts[0]
sg_list = partition.list_attached_storage_groups()
storage_volume = None
for sg in sg_list:
try:
storage_volume = sg.storage_volumes.find(uuid=uuid)
break
except zhmcclient.NotFound:
continue
if not storage_volume:
raise click_exception(
"Storage volume with UUID '{uuid}' specified in "
"{where} was not found in any storage group attached "
"to partition '{part}' of CPC '{cpc}'.".
format(uuid=uuid, where=where, part=partition.name,
cpc=cpc_name),
error_format)
return storage_volume
if len(volume_parts) == 2: # format: SG/SV
sg_name, sv_name = volume_parts
sg_list = partition.list_attached_storage_groups()
sg = None
for _sg in sg_list:
if _sg.name == sg_name:
sg = _sg
break
if not sg:
raise click_exception(
"Storage group '{sg}' specified in {where} was not "
"found in the storage groups attached to partition '{part}' "
"of CPC '{cpc}'.".
format(sg=sg_name, where=where, part=partition.name,
cpc=cpc_name),
error_format)
try:
storage_volume = sg.storage_volumes.find(name=sv_name)
except zhmcclient.NotFound:
raise click_exception(
"Storage volume '{sv}' specified in {where} was not "
"found in the volumes of storage group '{sg}' attached to "
"partition '{part}' of CPC '{cpc}'.".
format(sv=sv_name, where=where, sg=sg_name,
part=partition.name, cpc=cpc_name),
error_format)
return storage_volume
raise click_exception(
"Invalid format for volume specified in {where}: '{vs}'. "
"CPC '{cpc}' has the storage management feature and therefore "
"only one of the formats 'SG/SV' or 'UUID' is supported.".
format(where=where, vs=volume_specifier, cpc=cpc_name),
error_format)
# pylint: disable=inconsistent-return-statements
def parse_volume_without_sm(volume_specifier, partition, where, error_format):
"""
Parse a volume specifier for a CPC without the storage management feature
(i.e. z13 and earlier) and return data identifying the storage volume as
a tuple of:
* the Hba resource object of the HBA named in the volume specifier
* the WWPN in the volume specifier
* the LUN in the volume specifier
The returned storage volume will always be of type FCP.
Parameters:
volume_specifier (string): The volume specifier, in one of these forms:
* "HBA/WWPN/LUN", where HBA is the name of the HBA resource in the
partition and WWPN and LUN identify the storage array and storage
volume thereon.
partition (Partition): The partition that has the storage group attached
that contains the specified volume.
where (string): Text stating where the volume has been specified, e.g.
"--volume option" (only used for messages).
error_format (string):
The error format (see ``--error-format`` general option, only used for
messages).
Returns:
tuple(zhmcclient.Hba, WWPN, LUN): Data identifying the storage volume,
see description.
"""
cpc_name = partition.manager.parent.name
volume_parts = volume_specifier.split('/')
if len(volume_parts) == 3: # format: HBA/WWPN/LUN
hba_name, wwpn, lun = volume_parts
try:
hba = partition.hbas.find(name=hba_name)
except zhmcclient.NotFound:
raise click_exception(
"HBA '{hba}' specified in {where} was not found in partition "
"'{part}' of CPC '{cpc}'.".
format(hba=hba_name, where=where, part=partition.name,
cpc=cpc_name),
error_format)
return hba, wwpn, lun
raise click_exception(
"Invalid format for volume specified in {where}: '{vs}'. "
"CPC '{cpc}' does not have the storage management feature and "
"therefore only the format 'HBA/WWPN/LUN' is supported.".
format(where=where, vs=volume_specifier, cpc=cpc_name),
error_format)