Overview
In this how to we will cover how to modify your domain join action to use a connection info back to your domain. This will remove the need to create multiple parameters on your blueprint and to have username, passwords and domains listed.
Considerations
Have an understand of Python
Have admin access to create connection info
Know the credentials to the domain to enable the connection
Procedure
Creating the connection info
Logged in as an administrator, go to admin → External Systems (1) → Connection Info (2)
Click on New Connection Info
On the pop out, provide a Name, IP/HostName, Username, Password at a minimum and click Create
NOTE: You can place the host as a single domain controller, or, the complete domain.You will now see your new connection info created
Amending the Join OU in AD Domain Action
NOTE: Please backup the code or copy the code into a new action before modifying incase you need to role back
Go to Admin → Orchestration (1) → Actions (2)
Locate the Join OU in AD Domain Action and click on the name
The code you will change is below. Effectively we are doing the following:
Importing ConnectionInfo
Defining ConnectionInfo
Defining the new domain, ou, username and password
Doing validation against these new parameters#!/usr/local/bin/python from __future__ import print_function import sys from common.methods import set_progress import re from utilities.models import ConnectionInfo ci = ConnectionInfo.objects.get(name="Active Directory SovLabs") """ Example Hook to join a Windows server to a particular OU of an AD domain. You will need to create a connection info to the domain you require. Where you would put the IP/Hostname you MUST put the domain name This will help to connect to the first responding domain controller and also will be the domain that you will join this Virtual Machine too. You will need to ensure one additional parameter is available to your Blueprint which is named OU This is required to pass through the OU structure for where to place the VM Example: ou=prod,ou=servers,ou=Corporate,dc=mydomain,dc=com Additional parameters: In order to run the necessary script on the server, CloudBolt must know the username and password with which to log into the template. By default, CloudBolt uses the Administrator username. The password can be set using either the 'Windows Server Password' or 'VMware Template Password' parameters. If the username on the template is not Administrator, use the 'Server Username' parameter. This hook will be especially useful as a post-provisioning hook. Note: If the server is already in the specified domain (even if it is not in the requested OU), the script will not change anything and will print a message saying the server cannot be added to the domain again. Note: The password provided will be temporarily stored in plain text in a PowerShell script file on the system, but the file will be deleted when the task is complete. Testing this hook: To speed up the development cycle of testing this hook, it can be run from the command line. Using a completed server provision job, run `./join_domain_ou.py <job id>`. The job's originating order must have had the above parameters already set. """ def run(job, logger): # If the job this is associated with fails, don't do anything if job.status == "FAILURE": return "", "", "" server = job.server_set.last() if not server.is_windows(): msg = "Skipping joining domain for non-windows VM" return "", msg, "" if not server.resource_handler.cast().can_run_scripts_on_servers: logger.info("Skipping hook, cannot run scripts on guest") return "", "", "" set_progress("Joining OU in Domain based on parameters") ciou = server.get_value_for_custom_field("ou") ciusername = ci.username cipassword = ci.password cidomain = ci.ip fail_msg = "Parameter '{}' not set, cannot run hook" # confirm that all custom fields have been set if not cidomain: msg = fail_msg.format("cidomain") return "FAILURE", msg, "" elif not ciou: msg = fail_msg.format("ciou") return "FAILURE", msg, "" elif not ciusername: msg = fail_msg.format("ciusername") return "FAILURE", msg, "" elif not cipassword: msg = fail_msg.format("cipassword") return "FAILURE", msg, "" script = [ "Add-Computer ", '-DomainName "{}" '.format(cidomain.strip()), '-OUPath "{}" '.format(ciou.strip()), "-Credential ", "(", "New-Object ", "System.Management.Automation.PSCredential (", '"{}", '.format(ciusername.strip()), '(ConvertTo-SecureString "{}" -AsPlainText -Force)'.format(cipassword.strip()), ")) ", ] script = "".join(script) # For debugging. We'll eventually put this in the code base directly. username = server.get_credentials()["username"] msg = "Executing script on server using username '{}'".format(username) logger.info(msg) try: output = server.execute_script(script_contents=script) logger.info("Script returned output: {}".format(output)) except RuntimeError as err: set_progress(str(err)) # If the error is due to already being in the domain, it's OK errmsg = re.sub(r"\r", "", str(err)) errmsg = re.sub(r"\n", "", errmsg) found = re.search(r"because it is already in that domain", errmsg) if not found: return "FAILURE", str(err), "" return "", "", "" if __name__ == "__main__": from jobs.models import Job from utilities.logger import ThreadLogger logger = ThreadLogger(__name__) job_id = sys.argv[1] job = Job.objects.get(id=job_id) print(run(job, logger))
Save your code and do some testing.
NOTE: You can modify this in any form you require, you could eventually change the ci = value to be dynamic to select from the blueprint so you could select a domain, and that domain could be a part of the ConnectionInfo name.
For Example:
Drop down of domain.bcd , domaine.fgh, domaini.jkl
Your connection info names could be Active Directory domaina.bcd and so forth for each domain.
Then in your script you amend to be something like:domainselection = "Active Directory {}".format(server.domainselect) ci = ConnectionInfo.objects.get(name=domainselection)
This would then look for a parameter on your blueprint called domainselect, and put the domain into the connection info string so you could make multiple different domain connections with the one script.
Additional information
CloudBolt blueprint actions document : https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/blueprint-actions
CloudBolt action document : https://docs.cloudbolt.io/articles/#!cloudbolt-latest-docs/actions
0 Comments