Skip to content
Snippets Groups Projects
Commit 122362de authored by Kurt Kirsten's avatar Kurt Kirsten
Browse files

1

parent 5223d6c7
No related branches found
No related tags found
No related merge requests found
# Script-Sammlung # Script-Sammlung
\ No newline at end of file
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://gitlab.hrz.tu-chemnitz.de/kuki797d--tu-dresden.de/script-sammlung.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.hrz.tu-chemnitz.de/kuki797d--tu-dresden.de/script-sammlung/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
# Clustershell Auto-Update Script
- **Setup**
- ```clustershell_add_cfg``` to ```/home/jmp```
- ```nagios/check_update_clustershell_ips``` to ```/usr/lib/nagios/plugins```
- ```systemd/*``` to ```/etc/systemd/system``` and start/enable
- */etc/nagios/nrpe.cfg*
- ```command[clsh_update]=sudo -u jmp /usr/lib/nagios/plugins/check_update_clustershell_ips```
- **clustershell_add_cfg/clsh_get_cfg.py**
- This script checks all VMs with the custom field "SERVICE_CLASS"=="PaaS" and tries to read out the guest-os from the vm-object as well as the custom field "PRIMARY_IP_ADDRESS". If everything is available the script will check the guest-os-string for any "identifiers" under any "os_configuration" as given in the config. The ip-addresses for each "os_configuration" for each "vcenter_configuration" are temporarily written to a file under /tmp. After everything is done, the temporary files of each "os_configuration" are combined, sorted and written to the "outputfile" given in the config. (so that the same "os_configuration" from different "vcenter_configuration" are combined as well)
- *Required Parameters*: --config
- *Config*: See ```clustershell_add_cfg``` for examples
\ No newline at end of file
#!/usr/bin/python3
import json
import argparse
import warnings
from os import remove
from os.path import isfile, exists, basename
from atexit import register
from sys import exit, stdout
import datetime
from socket import inet_aton
import struct
from pyVim.connect import *
from pyVmomi import vmodl, vim
# This script checks all VMs with the custom field "SERVICE_CLASS"=="PaaS" and tries to read out the guest-os from the vm-object as well as the custom field "PRIMARY_IP_ADDRESS".
# If everything is available the script will check the guest-os-string for any "identifiers" under any "os_configuration" as given in the config.
# The ip-addresses for each "os_configuration" for each "vcenter_configuration" are temporarily written to a file under /tmp.
# After everything is done, the temporary files of each "os_configuration" are combined, sorted and written to the "outputfile" given in the config.
# (so that the same "os_configuration" from different "vcenter_configuration" are combined as well)
def arg_parser():
# Just the arguments parser
my_parser = argparse.ArgumentParser(description="Metric script")
my_parser.add_argument(
"--config",
action="store",
type=str,
help="Path to a config file.",
)
args = my_parser.parse_args()
if args.config is not None:
if not isfile(args.config):
print("The path specified from -C / --config does not exist")
exit()
else:
print("config file is required. -C / --config")
exit()
return args
def sort_ips(ips):
return sorted(ips, key=lambda ip: struct.unpack("!L", inet_aton(ip))[0])
def main():
# argparser
warnings.filterwarnings("ignore", category=DeprecationWarning)
s = ssl.SSLContext()
s.verify_mode = ssl.CERT_NONE
args = arg_parser()
with open(args.config) as json_file:
loaded = json.load(json_file)
vcenters = loaded["vcenter_configuration"]
WARNINGS = loaded["warnings"]
for vcenter in vcenters:
# connect
print("Starting with VCenter {}".format(vcenter["hostname"]))
si = SmartConnect(
host=vcenter["hostname"],
user=vcenter["username"],
pwd=vcenter["password"],
sslContext=s,
port=443,
)
register(Disconnect, si)
content = si.RetrieveContent()
# the custom attributes are mapped to a key (a unique number)
# we first have to get this id trough customFieldsmanager
SERVICE_CLASS_ID = None
PRIMARY_IP_ADDRESS_ID = None
cfm = content.customFieldsManager
for some_field in cfm.field:
if some_field.name == "SERVICE_CLASS":
SERVICE_CLASS_ID = some_field.key
elif some_field.name == "PRIMARY_IP_ADDRESS":
PRIMARY_IP_ADDRESS_ID = some_field.key
if not SERVICE_CLASS_ID or not PRIMARY_IP_ADDRESS_ID:
print(
"Couldn't find the key to SERVICE_CLASS or PRIMARY_IP_ADDRESS custom field."
)
exit(1)
# get all avaialble vm objects
container = content.rootFolder
viewType = [vim.VirtualMachine]
recursive = True
containerView = content.viewManager.CreateContainerView(
container, viewType, recursive
)
vms = containerView.view
# those are the configurations for the operating systems
os_check_map = vcenter["os_configuration"]
# create some empty array, in which the ips are stored
for os in os_check_map:
os["ips"] = []
for vm in vms:
if vm.guest and vm.config and vm.config.extraConfig:
# check if PaaS is set
if any(
cfg_opt.key == SERVICE_CLASS_ID and cfg_opt.value == "PaaS"
for cfg_opt in vm.customValue
):
# check if vm.guest is accessible
if not vm.guest:
vm_guest_os = vm.config.guestFullName
else:
vm_guest_os = vm.guest.guestFullName
vm_ip_address = next(
(x for x in vm.customValue if x.key == PRIMARY_IP_ADDRESS_ID),
None,
)
vm_ip_address = (
vm_ip_address.value if vm_ip_address is not None else None
)
# check if guest os & ip address are accessible
if vm_guest_os is None or vm_ip_address is None:
if WARNINGS:
print(
"VM {} - can't read IP Address or GuestOS Name. Skipping.".format(
vm.name
)
)
continue
# go over all os-configurations given under the os_configuration key in the config file
for os in os_check_map:
# check if any of the identifiers given in the config file match anything in the guestFullName
if (
any(
identifier in vm_guest_os
for identifier in os["identifiers"]
)
and vm_ip_address not in os["ips"]
):
os["ips"].append(vm_ip_address)
# write temporary files to /tmp for this vcenter
for os in os_check_map:
if exists("/tmp"):
name = basename(os["outputfile"])
os["temporary_outputfile"] = (
"/tmp/" + name + vcenter["hostname"] + ".tmp"
)
else:
name = basename(os["outputfile"])
os["temporary_outputfile"] = name + vcenter["hostname"] + ".tmp"
# write the collected ip addresses of this vcenter to a temporary output file in /tmp
with open(os["temporary_outputfile"], "w") as f:
f.write("\n".join(os["ips"]) + "\n")
print("Done with VCenter {}".format(vcenter["hostname"]))
# map the temporary files to the output-file-path of the os
# (key = outputpath, value= array of temporary files that will be written to the outputpath)
file_map = {}
for vcenter in vcenters:
os_check_map = vcenter["os_configuration"]
for os in os_check_map:
if os["outputfile"] in file_map:
file_map[os["outputfile"]].append(os["temporary_outputfile"])
else:
file_map[os["outputfile"]] = [os["temporary_outputfile"]]
# write all temp files to their actual files
for output_file in file_map:
with open(output_file, "w") as write_file:
all_ips = []
# go over all temporary files belonging to the output_file of the current os
# and add any ip address in those files to all_ips
for read_file in file_map[output_file]:
with open(read_file, "r") as infile:
temp_ips = infile.read().split()
for temp_ip in temp_ips:
all_ips.append(temp_ip)
remove(read_file)
# sort all_ips by ip address
all_ips = sort_ips(all_ips)
write_file.write("\n".join(all_ips) + "\n")
if __name__ == "__main__":
main()
{
"_comment": "Warnings include: VMware tools not installed, no matching identifier in guest os string",
"warnings": false,
"_comment2": "Each vcenter has its own configuration, containing authentication & operating systems to be checked.",
"vcenter_configuration": [
{
"hostname": "vc-enterprise-lzr.zih.tu-dresden.de",
"username": "jmp@vsphere.local",
"password": "REDACTED",
"os_configuration": [
{
"identifiers": [
"CentOS"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/red"
},
{
"identifiers": [
"Debian"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/debian"
},
{
"identifiers": [
"Ubuntu"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/ubuntu"
},
{
"identifiers": [
"SUSE",
"SLES"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/suse"
}
]
},
{
"hostname": "vc-enterprise-tre.zih.tu-dresden.de",
"username": "jmp@vsphere.local",
"password": "REDACTED",
"os_configuration": [
{
"identifiers": [
"CentOS"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/red"
},
{
"identifiers": [
"Debian"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/debian"
},
{
"identifiers": [
"Ubuntu"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/ubuntu"
},
{
"identifiers": [
"SUSE",
"SLES"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/suse"
}
]
}
]
}
\ No newline at end of file
{
"_comment": "Warnings include: VMware tools not installed, no matching identifier in guest os string",
"warnings": false,
"_comment2": "Each vcenter has its own configuration, containing authentication & operating systems to be checked.",
"vcenter_configuration": [
{
"hostname": "vc-infrastructure-lzr.zih.tu-dresden.de",
"username": "jmp@vsphere.local",
"password": "REDACTED",
"os_configuration": [
{
"identifiers": [
"CentOS"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/red"
},
{
"identifiers": [
"Debian"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/debian"
},
{
"identifiers": [
"Ubuntu"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/ubuntu"
},
{
"identifiers": [
"SUSE",
"SLES"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/suse"
}
]
},
{
"hostname": "vc-infrastructure-tre.zih.tu-dresden.de",
"username": "jmp@vsphere.local",
"password": "REDACTED",
"os_configuration": [
{
"identifiers": [
"CentOS"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/red"
},
{
"identifiers": [
"Debian"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/debian"
},
{
"identifiers": [
"Ubuntu"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/ubuntu"
},
{
"identifiers": [
"SUSE",
"SLES"
],
"outputfile": "/etc/clustershell/groups.conf.d/vms/suse"
}
]
}
]
}
\ No newline at end of file
#!/bin/bash
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
time=$(systemctl status update_clustershell_ips | awk -F ' ' '{print $3'} | tail -1 | tr -d "\n")
status=$(systemctl status update_clustershell_ips | grep -o -P '(?<=status=).*(?=/)' | tail -1)
exitok() {
echo -n OK : Last run at $time
echo $*
exit $STATE_OK
}
exitwarning(){
echo -n WARNING : Last run at $time didnt complete successfully
echo $*
exit $STATE_WARNING
}
if [ $status = "0" ]; then
exitok
else
exitwarning
fi
[Unit]
Description=Update ips in /etc/clustershell/groups.conf.d/vms
[Service]
Type=simple
User=jmp
ExecStart=/home/jmp/clustershell_add_cfg/.venv/bin/python3 /home/jmp/clustershell_add_cfg/clsh_get_cfg.py --config /home/jmp/clustershell_add_cfg/config.json
Type=oneshot
\ No newline at end of file
[Unit]
Description=Run update clustershell ips script daily
[Timer]
#Execute job if it missed a run due to machine being off
Persistent=true
#Run 120 seconds after boot for the first time
OnBootSec=120
#Run every 1 hour thereafter
OnCalendar=*-*-* 20:00:00
#File describing job to execute
Unit=update_clustershell_ips.service
[Install]
WantedBy=timers.target
\ No newline at end of file
keine ahnung was das ist
baut glaube ich die berechtigungen von diensten der cmdb im vcenter nach
vcenter-username=kuki797d@vsphere.local
vcenter-password=
cmdb-username=kuki797d
cmdb-password=
cmdb-api=https://cmdb.zih.tu-dresden.de:31342
#!/usr/bin/python3
import requests
import json
import argparse
import warnings
import datetime
import time
from os.path import isfile
from atexit import register
from sys import exit, stdout
import re
# if used on windows its pyvim
# pip install pyvim pyvmomi
from pyVim.connect import *
from pyVmomi import vmodl, vim
# ########################## CMDB FUNCTIONS ###############################################
REQUEST_HEADER = {"content-type": "application/json"}
def establish_session(login, password, CMDB_API):
"""Authenticate with ZIH credentials.
Resulting session will be used for any further requests.
"""
login_header = {
**REQUEST_HEADER,
"X-RPC-Auth-Username": login,
"X-RPC-Auth-Password": password,
}
request = {"version": "2.0", "method": "idoit.login", "params": {}, "id": 1}
raw_response = requests.post(
CMDB_API, data=json.dumps(request), headers=login_header
)
response = raw_response.json()
if "result" in response and response["result"] != {}:
REQUEST_HEADER["X-RPC-Auth-Session"] = response["result"]["session-id"]
else:
print(response)
raise Exception("No session could be established")
def api_request(CMDB_API, method, params={}):
"""Very simple handler for cmdb requests."""
call = {"version": "2.0", "method": method, "params": params, "id": 1}
response = requests.post(CMDB_API, data=json.dumps(call), headers=REQUEST_HEADER)
return response.json()
def parse_category(obj_id, category, CMDB_API):
"""Execute 'cmdb.category.read' for given object and category.
Return False if no result was received.
"""
raw_response = api_request(
CMDB_API,
"cmdb.category.read",
{
"category": category,
"objID": obj_id,
"status": 2, # Show normal entries, ignore archived and deleted
},
)
if "result" not in raw_response:
return False
return raw_response["result"]
def parse_object(obj_id, CMDB_API):
"""Execute 'cmdb.category.read' for given object and category.
Return False if no result was received.
"""
raw_response = api_request(
CMDB_API,
"cmdb.objects.read",
{"filter": [{"type": obj_id}]},
)
if "result" not in raw_response:
return False
return raw_response["result"]
# an array which contains vms that already have been sorted to a service
# some vms have multiple services
HANDLED_VMS = []
# [{
# "name": "Servicename",
# "id": 1,
# "contacts": [
# {
# "login": "kuki797d",
# "primary": true
# },
# {
# "login": "test999",
# "primary": false
# }
# ],
# "vms": [
# {
# "id": 82823,
# "vcenter_id": 1
# },
# {
# "id": 232332,
# "vcenter_id": 2
# }
# ]
# },]
# fetch_cmdb_data returns a list as described above
def fetch_cmdb_data(login, password, CMDB_API, debug):
"""Fetch all required Data from the CMDB. Returns a list of dictionaries, that contain the data."""
establish_session(login, password, CMDB_API)
SERVICES = []
# parse data from https://cmdb.zih.tu-dresden.de/?viewMode=1001&objTypeID=108
raw_services = parse_object(108, CMDB_API)
i = 0
service_len = len(raw_services)
print("Fetching CMDB Data...")
for service in raw_services:
service_map = {}
service_map["name"] = service["title"]
service_map["id"] = service["id"]
service_id = service["id"]
# parse data from contacts
service_contacts = parse_category(int(service_id), "C__CATG__CONTACT", CMDB_API)
service_map["contacts"] = []
primary_key_set = False
has_contacts = False
for contact in service_contacts:
# check of contact is really a person, can also be a group
if contact["contact"]["type"] == "C__OBJTYPE__PERSON":
if contact["contact"]["login"] != "":
contact_map = {}
contact_map["login"] = contact["contact"]["login"]
if int(contact["primary"]["value"]) == 1:
primary_key_set = True
contact_map["primary"] = True
else:
contact_map["primary"] = False
service_map["contacts"].append(contact_map)
has_contacts = True
if not has_contacts:
if debug:
print(
f"Warning: Service {service['title']} has no or no valid contacts."
)
if not primary_key_set:
try:
# set the first contact as primary, as there should always be at least one contact that has the primary flag
service_map["contacts"][0]["primary"] = True
if debug:
print(
f"Warning: Service {service['title']} has no primary key set. This would result in no VM-Admin Role being given. Giving this Role to the first available contact."
)
except IndexError:
pass
service_map["vms"] = []
# parse data from service components
service_components = parse_category(
int(service_id), "C__CATG__IT_SERVICE_COMPONENTS", CMDB_API
)
has_vms = False
for component in service_components:
if component["connected_object"]["type"] == "C__OBJTYPE__VIRTUAL_SERVER":
raw_name = component["connected_object"]["title"]
# vms should always be only mapped to one service
# some vms are in multiple services, this would result in inconsistent behaviour
# the vm would be moved around in multiple serivce-folders
if raw_name not in HANDLED_VMS:
HANDLED_VMS.append(raw_name)
vmname = raw_name.replace("(", "").replace(")", "")
vm_id = vmname.split("-")[-2]
vm_vcenter_id = vmname.split("-")[-1]
vm_map = {"id": vm_id, "vcenter_id": vm_vcenter_id}
service_map["vms"].append(vm_map)
has_vms = True
if not has_vms:
if debug:
print(
f"Warning: Service {service['title']} has no VMs registered to it."
)
SERVICES.append(service_map)
i += 1
stdout.write(f"Service {i} / {service_len}")
stdout.write("\r")
api_request(CMDB_API, "idoit.logout")
return SERVICES
# ###################################################################################
def arg_parser():
# Just the arguments parser
my_parser = argparse.ArgumentParser(description="Metric script")
my_parser.add_argument(
"--vcenter_hostname",
action="store",
type=str,
help="The VCenter hostname. Required if not given in authfile. Required if not given in authfile.",
)
my_parser.add_argument(
"--vcenter_username",
action="store",
type=str,
help="The username to log into the VCenter. Required if not given in authfile.",
)
my_parser.add_argument(
"--vcenter_password",
action="store",
type=str,
help="The password for your VCenter username. Required if not given in authfile.",
)
my_parser.add_argument(
"--cmdb_api",
action="store",
type=str,
help="CMDB Api including port. Example: https://cmdb.zih.tu-dresden.de:31342",
)
my_parser.add_argument(
"--cmdb_username",
action="store",
type=str,
help="The username to log into the CMDB. Required if not given in authfile.",
)
my_parser.add_argument(
"--cmdb_password",
action="store",
type=str,
help="The CMDB password for your username. Required if not given in authfile.",
)
my_parser.add_argument(
"--authfile",
"-A",
action="store",
type=str,
help="Authfile that may contain hostname, username and/or password. Authfile values will always override CMD args.",
)
my_parser.add_argument(
"--config",
action="store",
type=str,
help="Path to a config file.",
)
my_parser.add_argument(
"--debug",
"-D",
action=argparse.BooleanOptionalAction,
help="Enable debug mode",
)
my_parser.add_argument(
"--test",
action=argparse.BooleanOptionalAction,
help="Test Mode, doesn't apply anything. Temporarily creates folders but deletes them after.",
)
args = my_parser.parse_args()
# check if any authentication method is supplied
if (
args.vcenter_username is None
or args.vcenter_password is None
or args.cmdb_username is None
or args.cmdb_password is None
or args.cmdb_api is None
):
if args.authfile is None:
print("No / Not Enough Authentification Methods or CMDB Api supplied.")
exit()
else:
if not isfile(args.authfile):
print("The path specified from -A / --authfile does not exist")
exit()
else:
authfile = open(args.authfile, "r")
try:
for line in authfile:
if "vcenter-username" in line:
args.vcenter_username = line.split("=")[1].strip()
elif "vcenter-password" in line:
args.vcenter_password = line.split("=")[1].strip()
elif "cmdb-username" in line:
args.cmdb_username = line.split("=")[1].strip()
elif "cmdb-password" in line:
args.cmdb_password = line.split("=")[1].strip()
elif "cmdb-api" in line:
args.cmdb_api = line.split("=")[1].strip()
except Exception as E:
print(f"Error parsing authfile.\n{E}")
authfile.close()
authfile.close()
if args.test is None:
args.test = False
if args.config is not None:
if not isfile(args.config):
print("The path specified from -C / --config does not exist")
exit()
else:
print("config file is required. -C / --config")
exit()
return args
def find_root_folder(root_folder_id, content):
"""Find the working folder by ID. Returns the folder Object."""
container = content.rootFolder
container_view = content.viewManager.CreateContainerView(
container, [vim.Folder], True
)
# iterate over all folders
for folder in container_view.view:
# get the root Folder
folderid = str(folder).split("-")[-1]
folderid = re.sub("[^0-9]", "", folderid)
folderid = int(folderid)
if folderid == root_folder_id:
return folder
def check_if_vm_in_folder(vm, folder, content):
"""Check if vm is in folder. Returns a Boolean."""
vm_in_folder = False
container_view = content.viewManager.CreateContainerView(
folder, [vim.VirtualMachine], True
)
for n_vm in container_view.view:
if n_vm == vm:
vm_in_folder = True
break
return vm_in_folder
def check_if_folder_exist(folder_tsid, root_folder, content):
"""Check if a folder exists in the root_folder thats contains the folder_tsid"""
container_view = content.viewManager.CreateContainerView(
root_folder, [vim.Folder], True
)
for folderobj in container_view.view:
tsid = folderobj.name
if "TSID:" in folderobj.name:
tsid = tsid.split("TSID:")[1]
tsid = re.sub("[^0-9]", "", tsid)
tsid = int(tsid)
if tsid == folder_tsid:
return folderobj
return None
def wait_for_task(task):
while task.info.state not in [vim.TaskInfo.State.success, vim.TaskInfo.State.error]:
time.sleep(0.1)
print("Waiting for task to finish.")
if task.info.state == vim.TaskInfo.State.error:
return 1
return 0
def main():
# argparser
args = arg_parser()
if not args.debug:
print(
"Started the Script without --debug. Highly recommended to see changes made."
)
if args.test:
print(
"Started in Test-Mode. No changes will be made. Folders will be temporarily created and ALL empty folders under the root folder will be deleted in the end."
)
else:
print(
"Attention! This script will delete ALL empty folders under the given root folder. (Not Recursive)"
)
with open(args.config) as json_file:
VCENTERS = json.load(json_file)
SERVICES = fetch_cmdb_data(
args.cmdb_username, args.cmdb_password, args.cmdb_api, args.debug
)
print("Sucessfully fetched CMDB Data.")
for service in SERVICES:
for vcenter in VCENTERS:
# check if any vm from this service is located in this vcenter
# if not go to the next vcenter
found = False
for vm in service["vms"]:
if int(vm["vcenter_id"]) == int(vcenter["id"]):
found = True
if not found:
continue
if args.debug:
print(
f"Service: {service['name']} has VMs in VCenter {vcenter['hostname']}."
)
# Connect to the vcenter
warnings.filterwarnings("ignore", category=DeprecationWarning)
s = ssl.SSLContext()
s.verify_mode = ssl.CERT_NONE
si = SmartConnect(
host=vcenter["hostname"],
user=args.vcenter_username,
pwd=args.vcenter_password,
sslContext=s,
port=443,
)
register(Disconnect, si)
content = si.RetrieveContent()
container = content.rootFolder
auth_manager = content.authorizationManager
# get all roles from the system and map the name to the roleId
role_id_map = {}
for role in auth_manager.roleList:
role_id_map[role.name] = role.roleId
# finding the 'root' folder by id
ROOT_FOLDER = find_root_folder(int(vcenter["root_folder_id"]), content)
if ROOT_FOLDER is None:
print(f"Root Folder doesnt exist in {vcenter['hostname']}, Exiting")
exit(1)
# folder name like DHCP [TSID:236148]
name_length = len(service["name"]) + 9 + len(str(service["id"]))
if name_length > 79:
re = name_length - 79
foldername = f"{service['name'][:-re]} [TSID:{service['id']}]"
else:
foldername = f"{service['name']} [TSID:{service['id']}]"
# try to find a folder with this name else return None
get_folder = check_if_folder_exist(service["id"], ROOT_FOLDER, content)
# if return None create the Folder
if get_folder is None:
if args.debug:
print(
f"Creating Folder in VCenter {vcenter['hostname']}: {foldername} for Service {service['name']}"
)
working_folder = ROOT_FOLDER.CreateFolder(foldername)
else:
working_folder = get_folder
# retrieve existing permissions from folder
existing_permissions = auth_manager.RetrieveEntityPermissions(
working_folder, False
)
vm_admin_permission = []
vm_ko_admin_permission = []
# If a user exists with the role VM-Admin and VM-Ko-Admin,
# that is in the existing permissions but doesnt exist in the CMDB, remove this users permissions
unknown_users = []
# go over all existing permissions
for permission in existing_permissions:
# only interesting roles = VM-Admin and VM-Ko-Admin
if permission.roleId == role_id_map["VM-Admin"]:
vm_admin_permission.append(permission.principal)
unknown_users.append(str(permission.principal))
elif permission.roleId == role_id_map["VM-Ko-Admin"]:
vm_ko_admin_permission.append(permission.principal)
unknown_users.append(str(permission.principal))
# go over all contacts from this service
for contact in service["contacts"]:
# vcenter principal name like DOM\name
vcenter_principal_name = f"DOM\\{contact['login']}"
# if primary flag -> VM-Admin
if contact["primary"] == True:
# check if user already has this permission
if vcenter_principal_name in vm_admin_permission:
# remove this user from unknown users
unknown_users.remove(vcenter_principal_name)
# if not create it
else:
vcenter_set_permission_name = (
f"{contact['login']}@dom.tu-dresden.de"
)
perm = vim.AuthorizationManager.Permission()
perm.group = False
perm.principal = vcenter_set_permission_name
perm.propagate = True
perm.roleId = role_id_map["VM-Admin"]
if not args.test:
auth_manager.SetEntityPermissions(working_folder, [perm])
if args.debug:
print(
f"Adding permission VM-Admin for user {vcenter_set_permission_name} on folder {foldername}"
)
# if not primary flag -> VM-Ko-Admin
else:
# check if user already has those permissions
if vcenter_principal_name in vm_ko_admin_permission:
# remove this user from unknown users
unknown_users.remove(vcenter_principal_name)
else:
vcenter_set_permission_name = (
f"{contact['login']}@dom.tu-dresden.de"
)
perm = vim.AuthorizationManager.Permission()
perm.group = False
perm.principal = vcenter_set_permission_name
perm.propagate = True
perm.roleId = role_id_map["VM-Ko-Admin"]
if not args.test:
auth_manager.SetEntityPermissions(working_folder, [perm])
if args.debug:
print(
f"Adding permission VM-Ko-Admin for user {vcenter_set_permission_name} on folder {foldername}"
)
for user in unknown_users:
if args.debug:
print(
f"Removing permissions for {user} on Folder {foldername} as Users permissions were removed in the CMDB."
)
if not args.test:
auth_manager.RemoveEntityPermission(working_folder, user, False)
vms_to_move = []
vms = content.viewManager.CreateContainerView(
container, [vim.VirtualMachine], True
)
# iterate over all VMs in the VCenter and try to find the specified VMs by the ID
for vm_obj in vms.view:
for vm in service["vms"]:
# check if the vm is in the current vcenter
if int(vm["vcenter_id"]) != vcenter["id"]:
continue
vmid = str(vm_obj).replace("'", "").split("-")[1]
if vm["id"] == vmid:
if not check_if_vm_in_folder(vm_obj, working_folder, content):
vms_to_move.append(vm_obj)
if args.debug:
print(
f"VM {vm_obj.summary.config.name} will be moved to folder {foldername}."
)
# finally move the vms to the service folder
if len(vms_to_move) > 0:
if not args.test:
task = working_folder.MoveInto(vms_to_move)
ret_val = wait_for_task(task)
if ret_val == 1:
print(f"Error while moving vms: {str(vms_to_move)}")
# delete all empty folders across all vcenters after everything is done
for vcenter in VCENTERS:
# Connect to the vcenter
warnings.filterwarnings("ignore", category=DeprecationWarning)
s = ssl.SSLContext()
s.verify_mode = ssl.CERT_NONE
si = SmartConnect(
host=vcenter["hostname"],
user=args.vcenter_username,
pwd=args.vcenter_password,
sslContext=s,
port=443,
)
register(Disconnect, si)
content = si.RetrieveContent()
container = content.rootFolder
ROOT_FOLDER = find_root_folder(int(vcenter["root_folder_id"]), content)
if ROOT_FOLDER is None:
print(f"Root Folder doesnt exist in {vcenter['hostname']}, Exiting")
exit(1)
subfolders = content.viewManager.CreateContainerView(
ROOT_FOLDER, [vim.Folder], False
)
# delete all empty folders
for folder in subfolders.view:
# THIS WILL DELETE _ALL_ CHILDREN OF THIS FOLDER AS WELL WITHOUT ANY WARNING
# SO USE A DOUBLE CHECK TO REALLY MAKE SURE THE FOLDER IS EMPTY
check_content = folder.childEntity
if len(check_content) == 0:
check2 = content.viewManager.CreateContainerView(
folder, [vim.VirtualMachine, vim.Folder], True
)
if len(check2.view) == 0:
# shouldnt throw exceptions but a folder was created where i have no deletion rights
try:
if args.debug:
print(
f"Destroying Folder {str(folder.name)}, as it has no contents."
)
if not args.test:
folder.Destroy_Task()
ret_val = wait_for_task(task)
if ret_val == 1:
print(f"Error removing folder {folder.name}")
except:
pass
if __name__ == "__main__":
main()
[
{
"hostname": "vc-enterprise-tre.zih.tu-dresden.de",
"id": 1,
"root_folder_id": 369807
}
]
\ No newline at end of file
[
{
"name": "Servicename",
"id": 1,
"contacts": [
{
"login": "kuki797d",
"primary": true
},
{
"login": "test999",
"primary": false
}
],
"vms": [
{
"id": 82823,
"vcenter_id": 1
},
{
"id": 232332,
"vcenter_id": 2
}
]
},
{
"name": "Servicename2",
"id": 1,
"contacts": [
{
"login": "kuki797d",
"primary": true
},
{
"login": "test999",
"primary": false
}
],
"vms": [
{
"id": 82823,
"vcenter_id": 1
},
{
"id": 232332,
"vcenter_id": 2
}
]
}
]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment