003 File Manager
Current Path:
/usr/local/lib/python3.8/site-packages/salt/states
usr
/
local
/
lib
/
python3.8
/
site-packages
/
salt
/
states
/
📁
..
📄
__init__.py
(25 B)
📁
__pycache__
📄
acme.py
(5.08 KB)
📄
alias.py
(2.49 KB)
📄
alternatives.py
(6.75 KB)
📄
ansiblegate.py
(7.61 KB)
📄
apache.py
(3.95 KB)
📄
apache_conf.py
(2.72 KB)
📄
apache_module.py
(2.73 KB)
📄
apache_site.py
(2.66 KB)
📄
aptpkg.py
(1.42 KB)
📄
archive.py
(67.76 KB)
📄
artifactory.py
(6.84 KB)
📄
at.py
(7.54 KB)
📄
augeas.py
(10.57 KB)
📄
aws_sqs.py
(2.59 KB)
📄
azurearm_compute.py
(10.86 KB)
📄
azurearm_dns.py
(25.09 KB)
📄
azurearm_network.py
(87.86 KB)
📄
azurearm_resource.py
(27.22 KB)
📄
beacon.py
(7.58 KB)
📄
bigip.py
(96.63 KB)
📄
blockdev.py
(5.13 KB)
📄
boto3_elasticache.py
(48.01 KB)
📄
boto3_elasticsearch.py
(32.6 KB)
📄
boto3_route53.py
(37.54 KB)
📄
boto3_sns.py
(12.69 KB)
📄
boto_apigateway.py
(82.78 KB)
📄
boto_asg.py
(31.93 KB)
📄
boto_cfn.py
(11.53 KB)
📄
boto_cloudfront.py
(6.01 KB)
📄
boto_cloudtrail.py
(13.18 KB)
📄
boto_cloudwatch_alarm.py
(6.4 KB)
📄
boto_cloudwatch_event.py
(12.33 KB)
📄
boto_cognitoidentity.py
(13.69 KB)
📄
boto_datapipeline.py
(18.5 KB)
📄
boto_dynamodb.py
(29.32 KB)
📄
boto_ec2.py
(71.98 KB)
📄
boto_elasticache.py
(16.75 KB)
📄
boto_elasticsearch_domain.py
(12.27 KB)
📄
boto_elb.py
(55.1 KB)
📄
boto_elbv2.py
(12.19 KB)
📄
boto_iam.py
(69.16 KB)
📄
boto_iam_role.py
(27.12 KB)
📄
boto_iot.py
(25.33 KB)
📄
boto_kinesis.py
(16.69 KB)
📄
boto_kms.py
(12.11 KB)
📄
boto_lambda.py
(35.52 KB)
📄
boto_lc.py
(11.04 KB)
📄
boto_rds.py
(26 KB)
📄
boto_route53.py
(19.38 KB)
📄
boto_s3.py
(9.32 KB)
📄
boto_s3_bucket.py
(24.67 KB)
📄
boto_secgroup.py
(32.62 KB)
📄
boto_sns.py
(8.92 KB)
📄
boto_sqs.py
(7.97 KB)
📄
boto_vpc.py
(61.77 KB)
📄
bower.py
(8.26 KB)
📄
btrfs.py
(10.31 KB)
📄
cabal.py
(5.73 KB)
📄
ceph.py
(1.9 KB)
📄
chef.py
(3.68 KB)
📄
chocolatey.py
(17.33 KB)
📄
chronos_job.py
(4.6 KB)
📄
cimc.py
(14.32 KB)
📄
cisconso.py
(3.14 KB)
📄
cloud.py
(14.4 KB)
📄
cmd.py
(41.24 KB)
📄
composer.py
(8.38 KB)
📄
cron.py
(23.39 KB)
📄
cryptdev.py
(6.17 KB)
📄
csf.py
(9.98 KB)
📄
cyg.py
(7.05 KB)
📄
ddns.py
(4.2 KB)
📄
debconfmod.py
(6.33 KB)
📄
dellchassis.py
(24.49 KB)
📄
disk.py
(6.49 KB)
📄
docker_container.py
(85.27 KB)
📄
docker_image.py
(16.38 KB)
📄
docker_network.py
(36.34 KB)
📄
docker_volume.py
(6.72 KB)
📄
drac.py
(4.17 KB)
📄
dvs.py
(26.29 KB)
📄
elasticsearch.py
(20.38 KB)
📄
elasticsearch_index.py
(3.25 KB)
📄
elasticsearch_index_template.py
(3.67 KB)
📄
environ.py
(5.81 KB)
📄
eselect.py
(2.27 KB)
📄
esxcluster.py
(21.16 KB)
📄
esxdatacenter.py
(3.24 KB)
📄
esxi.py
(61.77 KB)
📄
esxvm.py
(18.86 KB)
📄
etcd_mod.py
(8.36 KB)
📄
ethtool.py
(7.84 KB)
📄
event.py
(2.48 KB)
📄
file.py
(299.79 KB)
📄
firewall.py
(1.33 KB)
📄
firewalld.py
(26.08 KB)
📄
gem.py
(7.13 KB)
📄
git.py
(124.23 KB)
📄
github.py
(27.25 KB)
📄
glance_image.py
(2.26 KB)
📄
glassfish.py
(21.47 KB)
📄
glusterfs.py
(12.12 KB)
📄
gnomedesktop.py
(7.47 KB)
📄
gpg.py
(5.28 KB)
📄
grafana.py
(12.11 KB)
📄
grafana4_dashboard.py
(17.31 KB)
📄
grafana4_datasource.py
(6.15 KB)
📄
grafana4_org.py
(7.73 KB)
📄
grafana4_user.py
(5.52 KB)
📄
grafana_dashboard.py
(17.74 KB)
📄
grafana_datasource.py
(5.31 KB)
📄
grains.py
(15.57 KB)
📄
group.py
(9.57 KB)
📄
heat.py
(9.69 KB)
📄
helm.py
(10.39 KB)
📄
hg.py
(6.33 KB)
📄
highstate_doc.py
(1.41 KB)
📄
host.py
(8.64 KB)
📄
http.py
(7.43 KB)
📄
icinga2.py
(9.07 KB)
📄
idem.py
(3.91 KB)
📄
ifttt.py
(2.12 KB)
📄
incron.py
(5.71 KB)
📄
influxdb08_database.py
(2.85 KB)
📄
influxdb08_user.py
(3.39 KB)
📄
influxdb_continuous_query.py
(2.81 KB)
📄
influxdb_database.py
(2.11 KB)
📄
influxdb_retention_policy.py
(4.82 KB)
📄
influxdb_user.py
(4.84 KB)
📄
infoblox_a.py
(4.24 KB)
📄
infoblox_cname.py
(4.19 KB)
📄
infoblox_host_record.py
(6.59 KB)
📄
infoblox_range.py
(6.85 KB)
📄
ini_manage.py
(12.67 KB)
📄
ipmi.py
(8.39 KB)
📄
ipset.py
(9.66 KB)
📄
iptables.py
(25.96 KB)
📄
jboss7.py
(23.95 KB)
📄
jenkins.py
(3.36 KB)
📄
junos.py
(17.78 KB)
📄
kapacitor.py
(6.46 KB)
📄
kernelpkg.py
(6.42 KB)
📄
keyboard.py
(2.01 KB)
📄
keystone.py
(27.12 KB)
📄
keystone_domain.py
(2.81 KB)
📄
keystone_endpoint.py
(4.69 KB)
📄
keystone_group.py
(3.25 KB)
📄
keystone_project.py
(3.36 KB)
📄
keystone_role.py
(2.33 KB)
📄
keystone_role_grant.py
(4.08 KB)
📄
keystone_service.py
(2.89 KB)
📄
keystone_user.py
(3.47 KB)
📄
keystore.py
(5.29 KB)
📄
kmod.py
(8.38 KB)
📄
kubernetes.py
(24.87 KB)
📄
layman.py
(2.44 KB)
📄
ldap.py
(19.78 KB)
📄
libcloud_dns.py
(5.7 KB)
📄
libcloud_loadbalancer.py
(5.66 KB)
📄
libcloud_storage.py
(5.13 KB)
📄
linux_acl.py
(24.43 KB)
📄
locale.py
(2.52 KB)
📄
logadm.py
(4.73 KB)
📄
logrotate.py
(3.86 KB)
📄
loop.py
(7.74 KB)
📄
lvm.py
(13.33 KB)
📄
lvs_server.py
(6.28 KB)
📄
lvs_service.py
(4.38 KB)
📄
lxc.py
(22.17 KB)
📄
lxd.py
(7.88 KB)
📄
lxd_container.py
(22.25 KB)
📄
lxd_image.py
(10.59 KB)
📄
lxd_profile.py
(7.11 KB)
📄
mac_assistive.py
(1.59 KB)
📄
mac_keychain.py
(5.59 KB)
📄
mac_xattr.py
(3.15 KB)
📄
macdefaults.py
(2.65 KB)
📄
macpackage.py
(6.76 KB)
📄
makeconf.py
(6.87 KB)
📄
marathon_app.py
(4.45 KB)
📄
mdadm_raid.py
(6.41 KB)
📄
memcached.py
(3.95 KB)
📄
modjk.py
(2.84 KB)
📄
modjk_worker.py
(6.49 KB)
📄
module.py
(17.99 KB)
📄
mongodb_database.py
(1.65 KB)
📄
mongodb_user.py
(6.26 KB)
📄
monit.py
(2.68 KB)
📄
mount.py
(49.55 KB)
📄
mssql_database.py
(3 KB)
📄
mssql_login.py
(3.64 KB)
📄
mssql_role.py
(2.37 KB)
📄
mssql_user.py
(3.51 KB)
📄
msteams.py
(2.53 KB)
📄
mysql_database.py
(6.05 KB)
📄
mysql_grants.py
(8.49 KB)
📄
mysql_query.py
(13.07 KB)
📄
mysql_user.py
(9.51 KB)
📄
net_napalm_yang.py
(9.15 KB)
📄
netacl.py
(31.92 KB)
📄
netconfig.py
(33.42 KB)
📄
netntp.py
(12.48 KB)
📄
netsnmp.py
(11.33 KB)
📄
netusers.py
(16.1 KB)
📄
network.py
(23.7 KB)
📄
neutron_network.py
(3.96 KB)
📄
neutron_secgroup.py
(4 KB)
📄
neutron_secgroup_rule.py
(4.75 KB)
📄
neutron_subnet.py
(4.29 KB)
📄
nexus.py
(4.97 KB)
📄
nfs_export.py
(4.92 KB)
📄
nftables.py
(19.5 KB)
📄
npm.py
(11.21 KB)
📄
ntp.py
(2.12 KB)
📄
nxos.py
(10.67 KB)
📄
nxos_upgrade.py
(3.5 KB)
📄
openstack_config.py
(3.26 KB)
📄
openvswitch_bridge.py
(3.13 KB)
📄
openvswitch_port.py
(17.25 KB)
📄
opsgenie.py
(4.07 KB)
📄
pagerduty.py
(1.89 KB)
📄
pagerduty_escalation_policy.py
(5.42 KB)
📄
pagerduty_schedule.py
(6.09 KB)
📄
pagerduty_service.py
(3.93 KB)
📄
pagerduty_user.py
(1.18 KB)
📄
panos.py
(48.13 KB)
📄
pbm.py
(20.46 KB)
📄
pcs.py
(36.46 KB)
📄
pdbedit.py
(3.48 KB)
📄
pecl.py
(3.65 KB)
📄
pip_state.py
(37.55 KB)
📄
pkg.py
(127.05 KB)
📄
pkgbuild.py
(11.37 KB)
📄
pkgng.py
(685 B)
📄
pkgrepo.py
(23.59 KB)
📄
portage_config.py
(5.01 KB)
📄
ports.py
(5.65 KB)
📄
postgres_cluster.py
(4.19 KB)
📄
postgres_database.py
(6.08 KB)
📄
postgres_extension.py
(5.68 KB)
📄
postgres_group.py
(8.52 KB)
📄
postgres_initdb.py
(2.84 KB)
📄
postgres_language.py
(3.94 KB)
📄
postgres_privileges.py
(7.86 KB)
📄
postgres_schema.py
(4.34 KB)
📄
postgres_tablespace.py
(6.62 KB)
📄
postgres_user.py
(9.49 KB)
📄
powerpath.py
(2.34 KB)
📄
probes.py
(15.06 KB)
📄
process.py
(1.32 KB)
📄
proxy.py
(4.94 KB)
📄
pushover.py
(3.13 KB)
📄
pyenv.py
(6.07 KB)
📄
pyrax_queues.py
(2.97 KB)
📄
quota.py
(1.4 KB)
📄
rabbitmq_cluster.py
(1.84 KB)
📄
rabbitmq_plugin.py
(2.77 KB)
📄
rabbitmq_policy.py
(4.58 KB)
📄
rabbitmq_upstream.py
(7.9 KB)
📄
rabbitmq_user.py
(8.89 KB)
📄
rabbitmq_vhost.py
(3.04 KB)
📄
rbac_solaris.py
(6.67 KB)
📄
rbenv.py
(7.36 KB)
📄
rdp.py
(1.28 KB)
📄
redismod.py
(4.76 KB)
📄
reg.py
(19.22 KB)
📄
rsync.py
(4.45 KB)
📄
rvm.py
(6.56 KB)
📄
salt_proxy.py
(1.34 KB)
📄
saltmod.py
(30.88 KB)
📄
saltutil.py
(8.91 KB)
📄
schedule.py
(11.89 KB)
📄
selinux.py
(18.61 KB)
📄
serverdensity_device.py
(6.41 KB)
📄
service.py
(37.06 KB)
📄
slack.py
(4.98 KB)
📄
smartos.py
(44.89 KB)
📄
smtp.py
(2.3 KB)
📄
snapper.py
(7.24 KB)
📄
solrcloud.py
(4.48 KB)
📄
splunk.py
(4.32 KB)
📄
splunk_search.py
(3.17 KB)
📄
sqlite3.py
(14.7 KB)
📄
ssh_auth.py
(19.1 KB)
📄
ssh_known_hosts.py
(7.87 KB)
📄
stateconf.py
(494 B)
📄
status.py
(2.21 KB)
📄
statuspage.py
(17.29 KB)
📄
supervisord.py
(10.48 KB)
📄
svn.py
(8.14 KB)
📄
sysctl.py
(3.82 KB)
📄
syslog_ng.py
(2.97 KB)
📄
sysrc.py
(2.82 KB)
📄
telemetry_alert.py
(7.04 KB)
📄
test.py
(13.09 KB)
📄
testinframod.py
(1.35 KB)
📄
timezone.py
(3.42 KB)
📄
tls.py
(1.81 KB)
📄
tomcat.py
(9.72 KB)
📄
trafficserver.py
(8.82 KB)
📄
tuned.py
(3.32 KB)
📄
uptime.py
(1.87 KB)
📄
user.py
(35.43 KB)
📄
vagrant.py
(11.4 KB)
📄
vault.py
(3.28 KB)
📄
vbox_guest.py
(4.05 KB)
📄
victorops.py
(3.32 KB)
📄
virt.py
(80.06 KB)
📄
virtualenv_mod.py
(11.21 KB)
📄
webutil.py
(3.78 KB)
📄
win_certutil.py
(2.88 KB)
📄
win_dacl.py
(7.96 KB)
📄
win_dism.py
(13.02 KB)
📄
win_dns_client.py
(8.32 KB)
📄
win_firewall.py
(6.87 KB)
📄
win_iis.py
(31.56 KB)
📄
win_lgpo.py
(25.41 KB)
📄
win_license.py
(1.6 KB)
📄
win_network.py
(14.18 KB)
📄
win_path.py
(6.39 KB)
📄
win_pki.py
(5.56 KB)
📄
win_powercfg.py
(3.79 KB)
📄
win_servermanager.py
(10.4 KB)
📄
win_smtp_server.py
(10.01 KB)
📄
win_snmp.py
(6.64 KB)
📄
win_system.py
(13.78 KB)
📄
win_wua.py
(14.47 KB)
📄
win_wusa.py
(3.53 KB)
📄
winrepo.py
(2.74 KB)
📄
wordpress.py
(4.82 KB)
📄
x509.py
(26.98 KB)
📄
xml.py
(1.75 KB)
📄
xmpp.py
(2.61 KB)
📄
zabbix_action.py
(9.35 KB)
📄
zabbix_host.py
(27.25 KB)
📄
zabbix_hostgroup.py
(5.64 KB)
📄
zabbix_mediatype.py
(16.89 KB)
📄
zabbix_template.py
(35.14 KB)
📄
zabbix_user.py
(15.76 KB)
📄
zabbix_usergroup.py
(9.64 KB)
📄
zabbix_usermacro.py
(9.69 KB)
📄
zabbix_valuemap.py
(8.11 KB)
📄
zcbuildout.py
(5.16 KB)
📄
zenoss.py
(2.89 KB)
📄
zfs.py
(34.27 KB)
📄
zk_concurrency.py
(5.81 KB)
📄
zone.py
(46.49 KB)
📄
zookeeper.py
(11.53 KB)
📄
zpool.py
(13.08 KB)
Editing: smartos.py
""" Management of SmartOS Standalone Compute Nodes :maintainer: Jorge Schrauwen <sjorge@blackdot.be> :maturity: new :depends: vmadm, imgadm :platform: smartos .. versionadded:: 2016.3.0 .. code-block:: yaml vmtest.example.org: smartos.vm_present: - config: reprovision: true - vmconfig: image_uuid: c02a2044-c1bd-11e4-bd8c-dfc1db8b0182 brand: joyent alias: vmtest quota: 5 max_physical_memory: 512 tags: label: 'test vm' owner: 'sjorge' nics: "82:1b:8e:49:e9:12": nic_tag: trunk mtu: 1500 ips: - 172.16.1.123/16 - 192.168.2.123/24 vlan_id: 10 "82:1b:8e:49:e9:13": nic_tag: trunk mtu: 1500 ips: - dhcp vlan_id: 30 filesystems: "/bigdata": source: "/bulk/data" type: lofs options: - ro - nodevices kvmtest.example.org: smartos.vm_present: - vmconfig: brand: kvm alias: kvmtest cpu_type: host ram: 512 vnc_port: 9 tags: label: 'test kvm' owner: 'sjorge' disks: disk0: size: 2048 model: virtio compression: lz4 boot: true nics: "82:1b:8e:49:e9:15": nic_tag: trunk mtu: 1500 ips: - dhcp vlan_id: 30 docker.example.org: smartos.vm_present: - config: auto_import: true reprovision: true - vmconfig: image_uuid: emby/embyserver:latest brand: lx alias: mydockervm quota: 5 max_physical_memory: 1024 tags: label: 'my emby docker' owner: 'sjorge' resolvers: - 172.16.1.1 nics: "82:1b:8e:49:e9:18": nic_tag: trunk mtu: 1500 ips: - 172.16.1.118/24 vlan_id: 10 filesystems: "/config: source: "/vmdata/emby_config" type: lofs options: - nodevices cleanup_images: smartos.image_vacuum .. note:: Keep in mind that when removing properties from vmconfig they will not get removed from the vm's current configuration, except for nics, disk, tags, ... they get removed via add_*, set_*, update_*, and remove_*. Properties must be manually reset to their default value. The same behavior as when using 'vmadm update'. .. warning:: For HVM (bhyve and KVM) brands the `image_uuid` field should go on the boot disks, this disk should NOT have a size specified. (See man vmadm) """ import json import logging import os import salt.utils.atomicfile import salt.utils.data import salt.utils.files log = logging.getLogger(__name__) # Define the state's virtual name __virtualname__ = "smartos" def __virtual__(): """ Provides smartos state provided for SmartOS """ if "vmadm.create" in __salt__ and "imgadm.list" in __salt__: return True else: return ( False, "{} state module can only be loaded on SmartOS compute nodes".format( __virtualname__ ), ) def _split_docker_uuid(uuid): """ Split a smartos docker uuid into repo and tag """ if uuid: uuid = uuid.split(":") if len(uuid) == 2: tag = uuid[1] repo = uuid[0] return repo, tag return None, None def _is_uuid(uuid): """ Check if uuid is a valid smartos uuid Example: e69a0918-055d-11e5-8912-e3ceb6df4cf8 """ if uuid and list(len(x) for x in uuid.split("-")) == [8, 4, 4, 4, 12]: return True return False def _is_docker_uuid(uuid): """ Check if uuid is a valid smartos docker uuid Example plexinc/pms-docker:plexpass """ repo, tag = _split_docker_uuid(uuid) return not (not repo and not tag) def _load_config(): """ Loads and parses /usbkey/config """ config = {} if os.path.isfile("/usbkey/config"): with salt.utils.files.fopen("/usbkey/config", "r") as config_file: for optval in config_file: optval = salt.utils.stringutils.to_unicode(optval) if optval[0] == "#": continue if "=" not in optval: continue optval = optval.split("=") config[optval[0].lower()] = optval[1].strip().strip('"') log.debug("smartos.config - read /usbkey/config: %s", config) return config def _write_config(config): """ writes /usbkey/config """ try: with salt.utils.atomicfile.atomic_open("/usbkey/config", "w") as config_file: config_file.write("#\n# This file was generated by salt\n#\n") for prop in salt.utils.odict.OrderedDict(sorted(config.items())): if " " in str(config[prop]): if not config[prop].startswith('"') or not config[prop].endswith( '"' ): config[prop] = '"{}"'.format(config[prop]) config_file.write( salt.utils.stringutils.to_str("{}={}\n".format(prop, config[prop])) ) log.debug("smartos.config - wrote /usbkey/config: %s", config) except OSError: return False return True def _parse_vmconfig(config, instances): """ Parse vm_present vm config """ vmconfig = None if isinstance(config, (salt.utils.odict.OrderedDict)): vmconfig = salt.utils.odict.OrderedDict() for prop in config: if prop not in instances: vmconfig[prop] = config[prop] else: if not isinstance(config[prop], (salt.utils.odict.OrderedDict)): continue vmconfig[prop] = [] for instance in config[prop]: instance_config = config[prop][instance] instance_config[instances[prop]] = instance ## some property are lowercase if "mac" in instance_config: instance_config["mac"] = instance_config["mac"].lower() ## calculate mac from vrrp_vrid if "vrrp_vrid" in instance_config: instance_config["mac"] = "00:00:5e:00:01:{}".format( hex(int(instance_config["vrrp_vrid"])) .split("x")[-1] .zfill(2), ) vmconfig[prop].append(instance_config) else: log.error("smartos.vm_present::parse_vmconfig - failed to parse") return vmconfig def _get_instance_changes(current, state): """ get modified properties """ # get keys current_keys = set(current.keys()) state_keys = set(state.keys()) # compare configs changed = salt.utils.data.compare_dicts(current, state) for change in salt.utils.data.compare_dicts(current, state): if change in changed and changed[change]["old"] == "": del changed[change] if change in changed and changed[change]["new"] == "": del changed[change] return changed def _copy_lx_vars(vmconfig): # NOTE: documentation on dockerinit: https://github.com/joyent/smartos-live/blob/master/src/dockerinit/README.md if "image_uuid" in vmconfig: # NOTE: retrieve tags and type from image imgconfig = __salt__["imgadm.get"](vmconfig["image_uuid"]).get("manifest", {}) imgtype = imgconfig.get("type", "zone-dataset") imgtags = imgconfig.get("tags", {}) # NOTE: copy kernel_version (if not specified in vmconfig) if "kernel_version" not in vmconfig and "kernel_version" in imgtags: vmconfig["kernel_version"] = imgtags["kernel_version"] # NOTE: copy docker vars if imgtype == "docker": vmconfig["docker"] = True vmconfig["kernel_version"] = vmconfig.get("kernel_version", "4.3.0") if "internal_metadata" not in vmconfig: vmconfig["internal_metadata"] = {} for var in imgtags.get("docker:config", {}): val = imgtags["docker:config"][var] var = "docker:{}".format(var.lower()) # NOTE: skip empty values if not val: continue # NOTE: skip or merge user values if var == "docker:env": try: val_config = json.loads( vmconfig["internal_metadata"].get(var, "") ) except ValueError as e: val_config = [] for config_env_var in ( val_config if isinstance(val_config, list) else json.loads(val_config) ): config_env_var = config_env_var.split("=") for img_env_var in val: if img_env_var.startswith("{}=".format(config_env_var[0])): val.remove(img_env_var) val.append("=".join(config_env_var)) elif var in vmconfig["internal_metadata"]: continue if isinstance(val, list): # NOTE: string-encoded JSON arrays vmconfig["internal_metadata"][var] = json.dumps(val) else: vmconfig["internal_metadata"][var] = val return vmconfig def config_present(name, value): """ Ensure configuration property is set to value in /usbkey/config name : string name of property value : string value of property """ name = name.lower() ret = {"name": name, "changes": {}, "result": None, "comment": ""} # load confiration config = _load_config() # handle bool and None value if isinstance(value, (bool)): value = "true" if value else "false" if not value: value = "" if name in config: if str(config[name]) == str(value): # we're good ret["result"] = True ret["comment"] = 'property {} already has value "{}"'.format(name, value) else: # update property ret["result"] = True ret["comment"] = 'updated property {} with value "{}"'.format(name, value) ret["changes"][name] = value config[name] = value else: # add property ret["result"] = True ret["comment"] = 'added property {} with value "{}"'.format(name, value) ret["changes"][name] = value config[name] = value # apply change if needed if not __opts__["test"] and ret["changes"]: ret["result"] = _write_config(config) if not ret["result"]: ret[ "comment" ] = 'Could not add property {} with value "{}" to config'.format( name, value ) return ret def config_absent(name): """ Ensure configuration property is absent in /usbkey/config name : string name of property """ name = name.lower() ret = {"name": name, "changes": {}, "result": None, "comment": ""} # load configuration config = _load_config() if name in config: # delete property ret["result"] = True ret["comment"] = "property {} deleted".format(name) ret["changes"][name] = None del config[name] else: # we're good ret["result"] = True ret["comment"] = "property {} is absent".format(name) # apply change if needed if not __opts__["test"] and ret["changes"]: ret["result"] = _write_config(config) return ret def source_present(name, source_type="imgapi"): """ Ensure an image source is present on the computenode name : string source url source_type : string source type (imgapi or docker) """ ret = {"name": name, "changes": {}, "result": None, "comment": ""} if name in __salt__["imgadm.sources"](): # source is present ret["result"] = True ret["comment"] = "image source {} is present".format(name) else: # add new source if __opts__["test"]: res = {} ret["result"] = True else: res = __salt__["imgadm.source_add"](name, source_type) ret["result"] = name in res if ret["result"]: ret["comment"] = "image source {} added".format(name) ret["changes"][name] = "added" else: ret["comment"] = "image source {} not added".format(name) if "Error" in res: ret["comment"] = "{}: {}".format(ret["comment"], res["Error"]) return ret def source_absent(name): """ Ensure an image source is absent on the computenode name : string source url """ ret = {"name": name, "changes": {}, "result": None, "comment": ""} if name not in __salt__["imgadm.sources"](): # source is absent ret["result"] = True ret["comment"] = "image source {} is absent".format(name) else: # remove source if __opts__["test"]: res = {} ret["result"] = True else: res = __salt__["imgadm.source_delete"](name) ret["result"] = name not in res if ret["result"]: ret["comment"] = "image source {} deleted".format(name) ret["changes"][name] = "deleted" else: ret["comment"] = "image source {} not deleted".format(name) if "Error" in res: ret["comment"] = "{}: {}".format(ret["comment"], res["Error"]) return ret def image_present(name): """ Ensure image is present on the computenode name : string uuid of image """ ret = {"name": name, "changes": {}, "result": None, "comment": ""} if _is_docker_uuid(name) and __salt__["imgadm.docker_to_uuid"](name): # docker image was imported ret["result"] = True ret["comment"] = "image {} ({}) is present".format( name, __salt__["imgadm.docker_to_uuid"](name), ) elif name in __salt__["imgadm.list"](): # image was already imported ret["result"] = True ret["comment"] = "image {} is present".format(name) else: # add image if _is_docker_uuid(name): # NOTE: we cannot query available docker images available_images = [name] else: available_images = __salt__["imgadm.avail"]() if name in available_images: if __opts__["test"]: ret["result"] = True res = {} if _is_docker_uuid(name): res["00000000-0000-0000-0000-000000000000"] = name else: res[name] = available_images[name] else: res = __salt__["imgadm.import"](name) if _is_uuid(name): ret["result"] = name in res elif _is_docker_uuid(name): ret["result"] = __salt__["imgadm.docker_to_uuid"](name) is not None if ret["result"]: ret["comment"] = "image {} imported".format(name) ret["changes"] = res else: ret["comment"] = "image {} was unable to be imported".format(name) else: ret["result"] = False ret["comment"] = "image {} does not exists".format(name) return ret def image_absent(name): """ Ensure image is absent on the computenode name : string uuid of image .. note:: computenode.image_absent will only remove the image if it is not used by a vm. """ ret = {"name": name, "changes": {}, "result": None, "comment": ""} uuid = None if _is_uuid(name): uuid = name if _is_docker_uuid(name): uuid = __salt__["imgadm.docker_to_uuid"](name) if not uuid or uuid not in __salt__["imgadm.list"](): # image not imported ret["result"] = True ret["comment"] = "image {} is absent".format(name) else: # check if image in use by vm if uuid in __salt__["vmadm.list"](order="image_uuid"): ret["result"] = False ret["comment"] = "image {} currently in use by a vm".format(name) else: # delete image if __opts__["test"]: ret["result"] = True else: image = __salt__["imgadm.get"](uuid) image_count = 0 if image["manifest"]["name"] == "docker-layer": # NOTE: docker images are made of multiple layers, loop over them while image: image_count += 1 __salt__["imgadm.delete"](image["manifest"]["uuid"]) if "origin" in image["manifest"]: image = __salt__["imgadm.get"](image["manifest"]["origin"]) else: image = None else: # NOTE: normal images can just be delete __salt__["imgadm.delete"](uuid) ret["result"] = uuid not in __salt__["imgadm.list"]() if image_count: ret["comment"] = "image {} and {} children deleted".format( name, image_count ) else: ret["comment"] = "image {} deleted".format(name) ret["changes"][name] = None return ret def image_vacuum(name): """ Delete images not in use or installed via image_present .. warning:: Only image_present states that are included via the top file will be detected. """ name = name.lower() ret = {"name": name, "changes": {}, "result": None, "comment": ""} # list of images to keep images = [] # retrieve image_present state data for host for state in __salt__["state.show_lowstate"](): # don't throw exceptions when not highstate run if "state" not in state: continue # skip if not from this state module if state["state"] != __virtualname__: continue # skip if not image_present if state["fun"] not in ["image_present"]: continue # keep images installed via image_present if "name" in state: if _is_uuid(state["name"]): images.append(state["name"]) elif _is_docker_uuid(state["name"]): state["name"] = __salt__["imgadm.docker_to_uuid"](state["name"]) if not state["name"]: continue images.append(state["name"]) # retrieve images in use by vms for image_uuid in __salt__["vmadm.list"](order="image_uuid"): if image_uuid not in images: images.append(image_uuid) # purge unused images ret["result"] = True for image_uuid in __salt__["imgadm.list"](): if image_uuid in images: continue image = __salt__["imgadm.get"](image_uuid) if image["manifest"]["name"] == "docker-layer": # NOTE: docker images are made of multiple layers, loop over them while image: image_uuid = image["manifest"]["uuid"] if image_uuid in __salt__["imgadm.delete"](image_uuid): ret["changes"][image_uuid] = None else: ret["result"] = False ret["comment"] = "failed to delete images" if "origin" in image["manifest"]: image = __salt__["imgadm.get"](image["manifest"]["origin"]) else: image = None else: # NOTE: normal images can just be delete if image_uuid in __salt__["imgadm.delete"](image_uuid): ret["changes"][image_uuid] = None else: ret["result"] = False ret["comment"] = "failed to delete images" if ret["result"] and not ret["changes"]: ret["comment"] = "no images deleted" elif ret["result"] and ret["changes"]: ret["comment"] = "images deleted" return ret def vm_present(name, vmconfig, config=None): """ Ensure vm is present on the computenode name : string hostname of vm vmconfig : dict options to set for the vm config : dict fine grain control over vm_present .. note:: The following configuration properties can be toggled in the config parameter. - kvm_reboot (true) - reboots of kvm zones if needed for a config update - auto_import (false) - automatic importing of missing images - auto_lx_vars (true) - copy kernel_version and docker:* variables from image - reprovision (false) - reprovision on image_uuid changes - enforce_tags (true) - false = add tags only, true = add, update, and remove tags - enforce_routes (true) - false = add tags only, true = add, update, and remove routes - enforce_internal_metadata (true) - false = add metadata only, true = add, update, and remove metadata - enforce_customer_metadata (true) - false = add metadata only, true = add, update, and remove metadata .. note:: State ID is used as hostname. Hostnames must be unique. .. note:: If hostname is provided in vmconfig this will take president over the State ID. This allows multiple states to be applied to the same vm. .. note:: The following instances should have a unique ID. - nic : mac - filesystem: target - disk : path or diskN for zvols e.g. disk0 will be the first disk added, disk1 the 2nd,... .. versionchanged:: 2019.2.0 Added support for docker image uuids, added auto_lx_vars configuration, documented some missing configuration options. """ name = name.lower() ret = {"name": name, "changes": {}, "result": None, "comment": ""} # config defaults state_config = config if config else {} config = { "kvm_reboot": True, "auto_import": False, "auto_lx_vars": True, "reprovision": False, "enforce_tags": True, "enforce_routes": True, "enforce_internal_metadata": True, "enforce_customer_metadata": True, } config.update(state_config) log.debug("smartos.vm_present::%s::config - %s", name, config) # map special vmconfig parameters # collections have set/remove handlers # instances have add/update/remove handlers and a unique id vmconfig_type = { "collection": ["tags", "customer_metadata", "internal_metadata", "routes"], "instance": { "nics": "mac", "disks": "path", "filesystems": "target", "pci_devices": "path", }, "create_only": ["filesystems"], } vmconfig_docker_keep = [ "docker:id", "docker:restartcount", ] vmconfig_docker_array = [ "docker:env", "docker:cmd", "docker:entrypoint", ] # parse vmconfig vmconfig = _parse_vmconfig(vmconfig, vmconfig_type["instance"]) log.debug("smartos.vm_present::%s::vmconfig - %s", name, vmconfig) # set hostname if needed if "hostname" not in vmconfig: vmconfig["hostname"] = name # prepare image_uuid if "image_uuid" in vmconfig: # NOTE: lookup uuid from docker uuid (normal uuid's are passed throuhg unmodified) # we must do this again if we end up importing a missing image later! docker_uuid = __salt__["imgadm.docker_to_uuid"](vmconfig["image_uuid"]) vmconfig["image_uuid"] = docker_uuid if docker_uuid else vmconfig["image_uuid"] # NOTE: import image (if missing and allowed) if vmconfig["image_uuid"] not in __salt__["imgadm.list"](): if config["auto_import"]: if not __opts__["test"]: res = __salt__["imgadm.import"](vmconfig["image_uuid"]) vmconfig["image_uuid"] = __salt__["imgadm.docker_to_uuid"]( vmconfig["image_uuid"] ) if vmconfig["image_uuid"] not in res: ret["result"] = False ret["comment"] = "failed to import image {}".format( vmconfig["image_uuid"] ) else: ret["result"] = False ret["comment"] = "image {} not installed".format(vmconfig["image_uuid"]) # prepare disk.*.image_uuid for disk in vmconfig["disks"] if "disks" in vmconfig else []: if "image_uuid" in disk and disk["image_uuid"] not in __salt__["imgadm.list"](): if config["auto_import"]: if not __opts__["test"]: res = __salt__["imgadm.import"](disk["image_uuid"]) if disk["image_uuid"] not in res: ret["result"] = False ret["comment"] = "failed to import image {}".format( disk["image_uuid"] ) else: ret["result"] = False ret["comment"] = "image {} not installed".format(disk["image_uuid"]) # docker json-array handling if "internal_metadata" in vmconfig: for var in vmconfig_docker_array: if var not in vmconfig["internal_metadata"]: continue if isinstance(vmconfig["internal_metadata"][var], list): vmconfig["internal_metadata"][var] = json.dumps( vmconfig["internal_metadata"][var] ) # copy lx variables if vmconfig["brand"] == "lx" and config["auto_lx_vars"]: # NOTE: we can only copy the lx vars after the image has bene imported vmconfig = _copy_lx_vars(vmconfig) # quick abort if things look wrong # NOTE: use explicit check for false, otherwise None also matches! if ret["result"] is False: return ret # check if vm exists if vmconfig["hostname"] in __salt__["vmadm.list"](order="hostname"): # update vm ret["result"] = True # expand vmconfig vmconfig = { "state": vmconfig, "current": __salt__["vmadm.get"](vmconfig["hostname"], key="hostname"), "changed": {}, "reprovision_uuid": None, } # prepare reprovision if "image_uuid" in vmconfig["state"]: vmconfig["reprovision_uuid"] = vmconfig["state"]["image_uuid"] vmconfig["state"]["image_uuid"] = vmconfig["current"]["image_uuid"] # disks need some special care if "disks" in vmconfig["state"]: new_disks = [] for disk in vmconfig["state"]["disks"]: path = False if "disks" in vmconfig["current"]: for cdisk in vmconfig["current"]["disks"]: if cdisk["path"].endswith(disk["path"]): path = cdisk["path"] break if not path: del disk["path"] else: disk["path"] = path new_disks.append(disk) vmconfig["state"]["disks"] = new_disks # process properties for prop in vmconfig["state"]: # skip special vmconfig_types if ( prop in vmconfig_type["instance"] or prop in vmconfig_type["collection"] or prop in vmconfig_type["create_only"] ): continue # skip unchanged properties if prop in vmconfig["current"]: if isinstance(vmconfig["current"][prop], (list)) or isinstance( vmconfig["current"][prop], (dict) ): if vmconfig["current"][prop] == vmconfig["state"][prop]: continue else: if "{}".format(vmconfig["current"][prop]) == "{}".format( vmconfig["state"][prop] ): continue # add property to changeset vmconfig["changed"][prop] = vmconfig["state"][prop] # process collections for collection in vmconfig_type["collection"]: # skip create only collections if collection in vmconfig_type["create_only"]: continue # enforcement enforce = config["enforce_{}".format(collection)] log.debug("smartos.vm_present::enforce_%s = %s", collection, enforce) # dockerinit handling if collection == "internal_metadata" and vmconfig["state"].get( "docker", False ): if "internal_metadata" not in vmconfig["state"]: vmconfig["state"]["internal_metadata"] = {} # preserve some docker specific metadata (added and needed by dockerinit) for var in vmconfig_docker_keep: val = vmconfig["current"].get(collection, {}).get(var, None) if val is not None: vmconfig["state"]["internal_metadata"][var] = val # process add and update for collection if ( collection in vmconfig["state"] and vmconfig["state"][collection] is not None ): for prop in vmconfig["state"][collection]: # skip unchanged properties if ( prop in vmconfig["current"][collection] and vmconfig["current"][collection][prop] == vmconfig["state"][collection][prop] ): continue # skip update if not enforcing if not enforce and prop in vmconfig["current"][collection]: continue # create set_ dict if "set_{}".format(collection) not in vmconfig["changed"]: vmconfig["changed"]["set_{}".format(collection)] = {} # add property to changeset vmconfig["changed"]["set_{}".format(collection)][prop] = vmconfig[ "state" ][collection][prop] # process remove for collection if ( enforce and collection in vmconfig["current"] and vmconfig["current"][collection] is not None ): for prop in vmconfig["current"][collection]: # skip if exists in state if ( collection in vmconfig["state"] and vmconfig["state"][collection] is not None ): if prop in vmconfig["state"][collection]: continue # create remove_ array if "remove_{}".format(collection) not in vmconfig["changed"]: vmconfig["changed"]["remove_{}".format(collection)] = [] # remove property vmconfig["changed"]["remove_{}".format(collection)].append(prop) # process instances for instance in vmconfig_type["instance"]: # skip create only instances if instance in vmconfig_type["create_only"]: continue # add or update instances if ( instance in vmconfig["state"] and vmconfig["state"][instance] is not None ): for state_cfg in vmconfig["state"][instance]: add_instance = True # find instance with matching ids for current_cfg in vmconfig["current"][instance]: if vmconfig_type["instance"][instance] not in state_cfg: continue if ( state_cfg[vmconfig_type["instance"][instance]] == current_cfg[vmconfig_type["instance"][instance]] ): # ids have matched, disable add instance add_instance = False changed = _get_instance_changes(current_cfg, state_cfg) update_cfg = {} # handle changes for prop in changed: update_cfg[prop] = state_cfg[prop] # handle new properties for prop in state_cfg: # skip empty props like ips, options,.. if ( isinstance(state_cfg[prop], (list)) and not state_cfg[prop] ): continue if prop not in current_cfg: update_cfg[prop] = state_cfg[prop] # update instance if update_cfg: # create update_ array if ( "update_{}".format(instance) not in vmconfig["changed"] ): vmconfig["changed"][ "update_{}".format(instance) ] = [] update_cfg[ vmconfig_type["instance"][instance] ] = state_cfg[vmconfig_type["instance"][instance]] vmconfig["changed"][ "update_{}".format(instance) ].append(update_cfg) if add_instance: # create add_ array if "add_{}".format(instance) not in vmconfig["changed"]: vmconfig["changed"]["add_{}".format(instance)] = [] # add instance vmconfig["changed"]["add_{}".format(instance)].append(state_cfg) # remove instances if ( instance in vmconfig["current"] and vmconfig["current"][instance] is not None ): for current_cfg in vmconfig["current"][instance]: remove_instance = True # find instance with matching ids if ( instance in vmconfig["state"] and vmconfig["state"][instance] is not None ): for state_cfg in vmconfig["state"][instance]: if vmconfig_type["instance"][instance] not in state_cfg: continue if ( state_cfg[vmconfig_type["instance"][instance]] == current_cfg[vmconfig_type["instance"][instance]] ): # keep instance if matched remove_instance = False if remove_instance: # create remove_ array if "remove_{}".format(instance) not in vmconfig["changed"]: vmconfig["changed"]["remove_{}".format(instance)] = [] # remove instance vmconfig["changed"]["remove_{}".format(instance)].append( current_cfg[vmconfig_type["instance"][instance]] ) # update vm if we have pending changes kvm_needs_start = False if not __opts__["test"] and vmconfig["changed"]: # stop kvm if disk updates and kvm_reboot if vmconfig["current"]["brand"] == "kvm" and config["kvm_reboot"]: if ( "add_disks" in vmconfig["changed"] or "update_disks" in vmconfig["changed"] or "remove_disks" in vmconfig["changed"] ): if vmconfig["state"]["hostname"] in __salt__["vmadm.list"]( order="hostname", search="state=running" ): kvm_needs_start = True __salt__["vmadm.stop"]( vm=vmconfig["state"]["hostname"], key="hostname" ) # do update rret = __salt__["vmadm.update"]( vm=vmconfig["state"]["hostname"], key="hostname", **vmconfig["changed"] ) if not isinstance(rret, (bool)) and "Error" in rret: ret["result"] = False ret["comment"] = "{}".format(rret["Error"]) else: ret["result"] = True ret["changes"][vmconfig["state"]["hostname"]] = vmconfig["changed"] if ret["result"]: if __opts__["test"]: ret["changes"][vmconfig["state"]["hostname"]] = vmconfig["changed"] if ( vmconfig["state"]["hostname"] in ret["changes"] and ret["changes"][vmconfig["state"]["hostname"]] ): ret["comment"] = "vm {} updated".format(vmconfig["state"]["hostname"]) if ( config["kvm_reboot"] and vmconfig["current"]["brand"] == "kvm" and not __opts__["test"] ): if vmconfig["state"]["hostname"] in __salt__["vmadm.list"]( order="hostname", search="state=running" ): __salt__["vmadm.reboot"]( vm=vmconfig["state"]["hostname"], key="hostname" ) if kvm_needs_start: __salt__["vmadm.start"]( vm=vmconfig["state"]["hostname"], key="hostname" ) else: ret["changes"] = {} ret["comment"] = "vm {} is up to date".format( vmconfig["state"]["hostname"] ) # reprovision (if required and allowed) if ( "image_uuid" in vmconfig["current"] and vmconfig["reprovision_uuid"] != vmconfig["current"]["image_uuid"] ): if config["reprovision"]: rret = __salt__["vmadm.reprovision"]( vm=vmconfig["state"]["hostname"], key="hostname", image=vmconfig["reprovision_uuid"], ) if not isinstance(rret, (bool)) and "Error" in rret: ret["result"] = False ret["comment"] = "vm {} updated, reprovision failed".format( vmconfig["state"]["hostname"] ) else: ret["comment"] = "vm {} updated and reprovisioned".format( vmconfig["state"]["hostname"] ) if vmconfig["state"]["hostname"] not in ret["changes"]: ret["changes"][vmconfig["state"]["hostname"]] = {} ret["changes"][vmconfig["state"]["hostname"]][ "image_uuid" ] = vmconfig["reprovision_uuid"] else: log.warning( "smartos.vm_present::%s::reprovision - " "image_uuid in state does not match current, " "reprovision not allowed", name, ) else: ret["comment"] = "vm {} failed to be updated".format( vmconfig["state"]["hostname"] ) if not isinstance(rret, (bool)) and "Error" in rret: ret["comment"] = "{}".format(rret["Error"]) else: # check required image installed ret["result"] = True # disks need some special care if "disks" in vmconfig: new_disks = [] for disk in vmconfig["disks"]: if "path" in disk: del disk["path"] new_disks.append(disk) vmconfig["disks"] = new_disks # create vm if ret["result"]: uuid = ( __salt__["vmadm.create"](**vmconfig) if not __opts__["test"] else True ) if not isinstance(uuid, (bool)) and "Error" in uuid: ret["result"] = False ret["comment"] = "{}".format(uuid["Error"]) else: ret["result"] = True ret["changes"][vmconfig["hostname"]] = vmconfig ret["comment"] = "vm {} created".format(vmconfig["hostname"]) return ret def vm_absent(name, archive=False): """ Ensure vm is absent on the computenode name : string hostname of vm archive : boolean toggle archiving of vm on removal .. note:: State ID is used as hostname. Hostnames must be unique. """ name = name.lower() ret = {"name": name, "changes": {}, "result": None, "comment": ""} if name not in __salt__["vmadm.list"](order="hostname"): # we're good ret["result"] = True ret["comment"] = "vm {} is absent".format(name) else: # delete vm if not __opts__["test"]: # set archive to true if needed if archive: __salt__["vmadm.update"]( vm=name, key="hostname", archive_on_delete=True ) ret["result"] = __salt__["vmadm.delete"](name, key="hostname") else: ret["result"] = True if not isinstance(ret["result"], bool) and ret["result"].get("Error"): ret["result"] = False ret["comment"] = "failed to delete vm {}".format(name) else: ret["comment"] = "vm {} deleted".format(name) ret["changes"][name] = None return ret def vm_running(name): """ Ensure vm is in the running state on the computenode name : string hostname of vm .. note:: State ID is used as hostname. Hostnames must be unique. """ name = name.lower() ret = {"name": name, "changes": {}, "result": None, "comment": ""} if name in __salt__["vmadm.list"](order="hostname", search="state=running"): # we're good ret["result"] = True ret["comment"] = "vm {} already running".format(name) else: # start the vm ret["result"] = ( True if __opts__["test"] else __salt__["vmadm.start"](name, key="hostname") ) if not isinstance(ret["result"], bool) and ret["result"].get("Error"): ret["result"] = False ret["comment"] = "failed to start {}".format(name) else: ret["changes"][name] = "running" ret["comment"] = "vm {} started".format(name) return ret def vm_stopped(name): """ Ensure vm is in the stopped state on the computenode name : string hostname of vm .. note:: State ID is used as hostname. Hostnames must be unique. """ name = name.lower() ret = {"name": name, "changes": {}, "result": None, "comment": ""} if name in __salt__["vmadm.list"](order="hostname", search="state=stopped"): # we're good ret["result"] = True ret["comment"] = "vm {} already stopped".format(name) else: # stop the vm ret["result"] = ( True if __opts__["test"] else __salt__["vmadm.stop"](name, key="hostname") ) if not isinstance(ret["result"], bool) and ret["result"].get("Error"): ret["result"] = False ret["comment"] = "failed to stop {}".format(name) else: ret["changes"][name] = "stopped" ret["comment"] = "vm {} stopped".format(name) return ret # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
Upload File
Create Folder