This commit is contained in:
root 2022-09-07 02:35:53 +02:00
parent cd4914ed55
commit def708e271
6 changed files with 487 additions and 5 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__

213
etalon Executable file
View File

@ -0,0 +1,213 @@
#!/usr/bin/perl
use strict; use warnings; use utf8;
use FindBin;
use lib $FindBin::Bin;
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
use Getopt::Long qw(:config no_ignore_case bundling);
use siteconf;
my %site_conf = siteconf::read;
my %opts = (
tmpmask => 24,
tmpip_skip => 0,
nodeploy => 0,
netmask => 24,
nouzem => 0,
noweb => 0,
nomysql => 0,
noreboot => 0
);
my $usage = <<EOT;
usage: $0 [OPTIONS..]
--site SITE vmware site (IP, DNS beállítások)
--clone-ip IP friss klón IP címe, default site_conf szerint
--tmpip IP ideiglenes IP cím az etalon készítés idejére
--tmpmask NNN ideiglenes címhez prefix hossz, default: 24
--tmpgw ideiglenes címhez default gw, default: .254
--tmpip-skip egyből az ideiglenes címet használja, nem állítja be
--nodeploy nincs hostnév és IP cím változtatás, vagy:
--hostname HH
--domain DOMAIN default site_conf szerint
--dns DNS[+DNS] default site_conf szerint
XXX--ntp NTPSERVER default site_conf szerint
--ip IP
--netmask NNN lehet prefix-length is (default: 24)
--gw GW default: .254
--datasize NNN /data mérete (`lvcreate -L` kapja) default: 50%FREE
--nouzem
--noweb
--nomysql
--mysql-root PWD mysql root jelszó, default: random
--border PREFIX installálj BORDERt (web + db localhost)
--border-db PREFIX .. de csak az adatbázisát
--border-web PREFIX .. de csak a webes részét
--border-dbpasswd PWD BORDER db jelszó, default: random
--border-web-dbhost HH db szerver hostnév \\_ /etc/hosts-ba kerül
--border-web-dbip HH db szerver IP cím /
--noreboot
EOT
GetOptions(
"site=s" => \$opts{site},
"clone-ip=s" => \$opts{clone_ip},
"tmpip=s" => \$opts{tmpip},
"tmpmask=s" => \$opts{tmpmask},
"tmpgw=s" => \$opts{tmpgw},
"tmpip-skip" => \$opts{tmpip_skip},
"nodeploy" => \$opts{nodeploy},
"hostname=s" => \$opts{hostname},
"domain=s" => \$opts{domain},
"dns=s" => \$opts{dns},
"ntp=s" => \$opts{ntp},
"ip=s" => \$opts{ip},
"netmask=s" => \$opts{netmask},
"gw=s" => \$opts{gw},
"datasize=s" => \$opts{datasize},
"nouzem" => \$opts{nouzem},
"noweb" => \$opts{noweb},
"nomysql" => \$opts{nomysql},
"mysql-root=s" => \$opts{mysql_root},
"border=s" => \$opts{border},
"border-db=s" => \$opts{border_db},
"border-web=s" => \$opts{border_web},
"border-web-dbhost=s" => \$opts{border_web_dbhost},
"border-web-dbip=s" => \$opts{border_web_dbip},
"border-dbpasswd=s" => \$opts{border_dbpasswd},
"noreboot" => \$opts{noreboot},
"help|h" => sub {print $usage; exit 0}
) or die $usage;
if (!defined $opts{site}) {
die "Kell --site.\n";
}
if (!exists $site_conf{$opts{site}}) {
die "site not found: $opts{site}\n";
}
for my $o (qw(dns ntp domain clone_ip mgmt_ssh_key postfix_relayhost)) {
if (!defined $opts{$o}) {
$opts{$o} = $site_conf{$opts{site}}->{$o};
}
}
chdir("$FindBin::Bin/..") or die "chdir() failed.\n";
my @vars;
my @skip;
if ($site_conf{$opts{site}}->{aptproxy}) {
push @vars, "aptproxy=$site_conf{$opts{site}}->{aptproxy}";
}
my $border_opts = 0;
for my $x ($opts{border}, $opts{border_web}, $opts{border_db}) {
$border_opts++ if $x;
}
die "Csak egy --border... opciót lehet egyszerre megadni\n" if $border_opts > 1;
if ($opts{border}) {
if ($opts{noweb} or $opts{nomysql}) {
die "--border opcióhoz kell web és mysql.\n";
}
push @vars, "border_prefix=$opts{border}";
} elsif ($opts{border_web}) {
die "Kell web.\n" if $opts{noweb};
die "Kell --mysql-root.\n" if !defined $opts{mysql_root};
die "Kell dbhost.\n" if !defined $opts{border_web_dbhost};
die "Kell dbip.\n" if !defined $opts{border_web_dbip};
die "Kell dbpasswd.\n" if !defined $opts{border_dbpasswd};
push @vars, "border_prefix=$opts{border_web}";
push @vars, "border_install_webonly=1";
push @vars, "border_dbhost=$opts{border_web_dbhost}";
push @vars, "border_dbip=$opts{border_web_dbip}";
} elsif ($opts{border_db}) {
die "Kell mysql.\n" if $opts{nomysql};
die "Kell --mysql-root.\n" if !defined $opts{mysql_root};
die "Kell dbpasswd.\n" if !defined $opts{border_dbpasswd};
push @vars, "border_prefix=$opts{border_db}";
push @vars, "border_install_dbonly=1";
} else {
push @skip, 'border';
}
if (!$opts{nodeploy}) {
die "Missing --hostname.\n" if !defined $opts{hostname};
die "Missing --ip.\n" if !defined $opts{ip};
if (!defined $opts{gw}) {
$opts{gw} = $opts{ip};
$opts{gw} =~ s/\.\d+$/.254/;
}
for my $x (qw(hostname domain dns ntp ip netmask gw)) {
push @vars, "$x=$opts{$x}";
}
}
if ($opts{datasize}) {
push @vars, "datasize=$opts{datasize}";
}
if ($opts{mysql_root}) {
push @vars, "mysql_root=$opts{mysql_root}";
}
if ($opts{border_dbpasswd}) {
push @vars, "border_dbpasswd=$opts{border_dbpasswd}";
}
if ($opts{postfix_relayhost}) {
push @vars, "postfix_relayhost=$opts{postfix_relayhost}";
}
if ($opts{tmpip}) {
if (!$opts{tmpip_skip}) {
if (!defined $opts{tmpgw}) {
$opts{tmpgw} = $opts{tmpip};
$opts{tmpgw} =~ s/\.\d+$/.254/;
}
my $cmd = "ansible -i etalon-debian, -e ansible_host=$opts{clone_ip} ".
"-u root -B 30 -P 0 -m shell -a '".
"sleep 3; DEV=\$(cd /sys/class/net; \\ls -1d e* | head -1);".
"ip a flu dev \$DEV; ".
"ip a add $opts{tmpip}/$opts{tmpmask} dev \$DEV; ".
"ip r add default via $opts{tmpgw}; ".
"ping -c 3 $opts{tmpgw}".
"' etalon-debian";
print "$cmd\n";
system $cmd;
exit 1 if $? > 0;
print "New IP address: $opts{tmpip}.\n";
sleep 5;
}
push @vars, "ansible_host=$opts{tmpip}";
}
my $vars = '';
for my $v (@vars) {
if ($v =~ /[\s'"]/) {
die "invalid character: '$v'.\n";
}
$vars .= " -e '$v'";
}
if ($opts{mgmt_ssh_key}) {
# szokoz van benne: -e 'aaa="bb cc"'
$vars .= " -e 'mgmt_ssh_key=\"$opts{mgmt_ssh_key}\"'";
}
for my $x (qw(deploy uzem web mysql reboot)) {
push @skip, $x if $opts{"no$x"};
}
my $skip = '';
if (scalar @skip) {
$skip = "--skip-tags=". join(',', @skip);
}
my $cmd = "ansible-playbook -i etalon-debian, -e ansible_host=$opts{clone_ip} $skip $vars etalon.yml";
print "$cmd\n";
system $cmd;
exit 1 if $? > 0;
if (!$opts{nodeploy}) {
print "\nadd to inventory:\n\n".
"echo '$opts{hostname} $opts{ip}' >> inventory\n\n";
}
# vim: set tabstop=4 shiftwidth=4 expandtab smarttab:

204
etalon_clone Executable file
View File

@ -0,0 +1,204 @@
#!/usr/bin/env python3
from pyVmomi import vim
import pyVim.connect
import atexit
import argparse
from pprint import pprint
import siteconf
site_conf = siteconf.read()
def get_args():
parser = argparse.ArgumentParser(
description='Clone VM from template')
parser.add_argument('-s', '--site',
required=True,
action='store',
help='Name of the site to create VM on')
parser.add_argument('-t', '--template',
required=False,
action='store',
help='Name of the template you wish to clone')
parser.add_argument('-v', '--vm-name',
required=True,
action='store',
help='Name of the VM you wish to make')
parser.add_argument('-c', '--cpu',
required=False,
type=int,
action='store',
default=1,
help='Set number of CPUs')
parser.add_argument('-m', '--memory',
required=False,
type=int,
action='store',
default=2048,
help='[MB] Set memory size')
parser.add_argument('-d', '--disk-size',
required=False,
type=int,
action='store',
default=0,
help='[GB] Resize LVM disk to this size')
parser.add_argument('--datastore',
required=False,
action='store',
default=None,
help='target datastore')
args = parser.parse_args()
args.disk_size = args.disk_size * 1024 * 1024
return args
def wait_for_task(task):
""" wait for a vCenter task to finish """
task_done = False
while not task_done:
if task.info.state == 'success':
return task.info.result
if task.info.state == 'error':
print("there was an error")
task_done = True
def get_obj(content, vimtype, name):
"""
Return an object by name, if name is None the
first found object is returned
"""
obj = None
container = content.viewManager.CreateContainerView(
content.rootFolder, vimtype, True)
for c in container.view:
if name:
if c.name == name:
obj = c
break
else:
obj = c
break
return obj
def clone_vm(content, template, vm_name, datacenter_name, datastore_name,
cluster_or_host):
datacenter = get_obj(content, [vim.Datacenter], datacenter_name)
destfolder = datacenter.vmFolder
datastore = get_obj(content, [vim.Datastore], datastore_name)
cluster = get_obj(content, [vim.ClusterComputeResource], cluster_or_host)
if cluster:
resource_pool = cluster.resourcePool
else:
host = get_obj(content, [vim.ComputeResource], cluster_or_host)
resource_pool = host.resourcePool
relospec = vim.vm.RelocateSpec()
relospec.datastore = datastore
relospec.pool = resource_pool
clonespec = vim.vm.CloneSpec()
clonespec.location = relospec
clonespec.powerOn = False
print("cloning VM...")
task = template.Clone(folder=destfolder, name=vm_name, spec=clonespec)
wait_for_task(task)
def extend_disk(content, vm_name, extend_to_kb):
vm = get_obj(content, [vim.VirtualMachine], vm_name)
for dev in vm.config.hardware.device:
#print("dev "+ dev.deviceInfo.label)
if hasattr(dev.backing, 'fileName'):
size_kb = dev.capacityInKB
if size_kb > 5 * 1024 * 1024: # lvm disk
if extend_to_kb > size_kb:
disk_spec = vim.vm.device.VirtualDeviceSpec()
disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
disk_spec.device = vim.vm.device.VirtualDisk()
disk_spec.device.key = dev.key
disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
disk_spec.device.backing.fileName = dev.backing.fileName
disk_spec.device.backing.diskMode = dev.backing.diskMode
disk_spec.device.controllerKey = dev.controllerKey
disk_spec.device.unitNumber = dev.unitNumber
disk_spec.device.capacityInKB = extend_to_kb
dev_changes = []
dev_changes.append(disk_spec)
spec = vim.vm.ConfigSpec()
spec.deviceChange = dev_changes
print("extending disk '"+ dev.deviceInfo.label +"' to "+ str(extend_to_kb) +" kB")
task = vm.ReconfigVM_Task(spec=spec)
wait_for_task(task)
def set_cpu_mem(content, vm_name, cpu, mem_mb):
vm = get_obj(content, [vim.VirtualMachine], vm_name)
spec = vim.vm.ConfigSpec()
spec.numCPUs = cpu
spec.memoryMB = mem_mb
print("Set cpu="+ str(cpu) +", memory="+ str(mem_mb) +" MB")
task = vm.ReconfigVM_Task(spec=spec)
wait_for_task(task)
def power_on(content, vm_name):
vm = get_obj(content, [vim.VirtualMachine], vm_name)
print("Powering on '"+ vm_name +"'")
task = vm.PowerOn()
wait_for_task(task)
def main():
args = get_args()
if not args.site in site_conf:
print(f"site not found: {args.site}")
exit(1)
site = site_conf[args.site];
#pprint(site)
si = pyVim.connect.SmartConnect(
host = site["vsphere"],
user = site["user"],
pwd = site["passwd"],
disableSslCertValidation = True
)
atexit.register(pyVim.connect.Disconnect, si)
content = si.RetrieveContent()
template_name = site["template"]
if args.template is not None:
template_name = args.template
template = get_obj(content, [vim.VirtualMachine], template_name)
if not template:
print("template not found")
exit(1)
vm = get_obj(content, [vim.VirtualMachine], args.vm_name)
if vm:
print("VM '"+ args.vm_name +"' exists.")
exit(1)
datastore = site["datastore"]
if args.datastore is not None:
datastore = args.datastore
clone_vm(content, template, args.vm_name, site["datacenter"],
datastore, site["cluster_or_host"])
set_cpu_mem(content, args.vm_name, args.cpu, args.memory)
extend_disk(content, args.vm_name, args.disk_size)
power_on(content, args.vm_name)
if __name__ == "__main__":
main()
# vim: set tabstop=4 shiftwidth=4 expandtab smarttab:

View File

@ -1,16 +1,19 @@
#!/bin/bash #!/bin/bash
ANSIBLE_DIR=/etc/ansible ANSIBLE_DIR=/etc/ansible
ANSIBLE_CMDB=/usr/local/bin/ansible-cmdb
OUTPUT=/var/www/def/public/facts.html OUTPUT=/var/www/def/public/facts.html
rm $ANSIBLE_DIR/gathered_facts/* rm $ANSIBLE_DIR/gathered_facts/*
ansible '!off,linux,windows' -m setup -f 5 --task-timeout 30 --tree $ANSIBLE_DIR/gathered_facts >/dev/null ansible '!off,linux,windows' -m setup -f 5 --task-timeout 30 --tree $ANSIBLE_DIR/gathered_facts >/dev/null
if [[ -x $ANSIBLE_CMDB ]]; then
INV="" INV=""
if [[ -r $ANSIBLE_DIR/cmdb-inventory ]]; then if [[ -r $ANSIBLE_DIR/cmdb-inventory ]]; then
INV="-i $ANSIBLE_DIR/cmdb-inventory" INV="-i $ANSIBLE_DIR/cmdb-inventory"
fi fi
/usr/local/bin/ansible-cmdb $INV -t html_fancy_split_overview $ANSIBLE_DIR/gathered_facts > $OUTPUT $ANSIBLE_CMDB $INV -t html_fancy_split_overview $ANSIBLE_DIR/gathered_facts > $OUTPUT
fi
# vim: set tabstop=4 shiftwidth=4 expandtab smarttab: # vim: set tabstop=4 shiftwidth=4 expandtab smarttab:

32
siteconf.pm Executable file
View File

@ -0,0 +1,32 @@
package siteconf;
use strict; use warnings;
use FindBin;
my $configuration = "$FindBin::Bin/../site.conf";
if (!open(FH, '<', $configuration)) {
die "Could not open configuration file: $configuration\n";
}
my %site_conf;
sub read {
my $site;
while (my $line = <FH>) {
chomp $line;
next if $line =~ /^#/;
next if $line !~ /\S/;
if ($line =~ /^\[([A-Za-z0-9_-]+)\]/) {
$site = $1;
$site_conf{$site} = {};
} elsif ($line =~ /^([A-Za-z0-9_-]+)\s+(.+)/) {
$site_conf{$site}->{$1} = $2;
} else {
die "invalid line in site_conf: $line\n";
}
}
close(FH);
return %site_conf;
}
1;
__END__
# vim: set tabstop=4 shiftwidth=4 expandtab smarttab:

29
siteconf.py Executable file
View File

@ -0,0 +1,29 @@
import os
import re
#from pprint import pprint
configuration = "{}/../site.conf".format(os.path.dirname(__file__))
site_conf = {}
def read():
with open(configuration, "r") as cf:
for line in cf:
line = line.rstrip();
if r := re.match('#', line):
continue
if r := re.match('\s*$', line):
continue
if r := re.match('\[([A-Za-z0-9_-]+)\]', line):
site = r[1]
site_conf[site] = {}
elif r := re.match('([A-Za-z0-9_-]+)\s+(.+)', line):
site_conf[site][r[1]] = r[2]
else:
print(f"invalid line in site_conf: {line}")
exit(1)
cf.close()
return site_conf
# vim: set tabstop=4 shiftwidth=4 expandtab smarttab: