Development tips for plugins
3 minute read
Run remote scripts with connection info objects
Connection info objects let a plugin run scripts against systems that have no REST API. They are also the way to run commands remotely on Windows servers via WinRM or on Linux servers via SSH.
Windows servers
- Create a connection info object and set its protocol to
winrm. - In the CMP CLI (shell_plus), set the transport type. Supported types are
ntlm,kerberos,credssp, andbasic, depending on what the target requires.
from utilities.models import ConnectionInfo
connection_info = ConnectionInfo.objects.get(name='my_connection_info')
connection_info.transport = 'ntlm'
connection_info.save()
Linux servers
- Create a connection info object and set its protocol to
ssh.
Execute a script on the connection info host
This works for both Windows and Linux targets. The example shows every parameter execute_script accepts, with its default.
script_contents = 'hostname'
connection_info.execute_script(
script_path=None,
script_contents=script_contents,
script_args=None,
timeout=120,
file_extension=None,
runas_username=None,
runas_password=None,
runas_key=None,
run_with_sudo=False,
)
Use stored credentials
When a plugin needs credentials, storing them in a connection info object keeps them out of your code. Go to Admin > Connection Info, create an entry with an easily identifiable name, then read it back in the plugin.
from utilities.models import ConnectionInfo
connection_info = ConnectionInfo.objects.get(name='my_connection_info')
ip = connection_info.ip
username = connection_info.username
password = connection_info.password
Use the requests library
Requests is the usual way to make HTTP calls from Python. For HTTPS endpoints, it verifies certificates against the root certificates supplied by the Certifi library. CMP can append additional certificates to that list or disable verification for installations that require it at Admin > SSL Root Certificates.
Rather than hard-coding a choice, call get_ssl_verification() so the plugin picks up whatever each instance is configured for. That keeps the same plugin working across instances.
import requests
from utilities.helpers import get_ssl_verification
response = requests.get('https://github.com', verify=get_ssl_verification())
Create child jobs from a parent job
A plugin can create child jobs under an existing job and have the parent wait until they finish. Creating a job takes the following arguments:
job_parameters: The parameters the job being run requires.type: A predefined job type, which determines what runs.owner: The profile of the user requesting the job.status:PENDINGwhen the job is first created.label: The job’s title.parent_job: The Job object that will be the parent.
Given a job object named parent_job, this creates a child job and waits for it:
from jobs.models import HookParameters, Job
# Example job parameters. Pass a JobParameter if the job expects one.
hook_params = {
"selected_sec_grps": [],
"resource_handler_id": self.resource_handler.id,
}
hook_param_obj = HookParameters.objects.create(arguments=hook_params)
job_type = "sync_rh_security_groups" # the type of job to run
child_job = Job(
job_parameters=hook_param_obj,
type=job_type,
owner=profile,
status="PENDING",
label="Sync security groups of resource handler",
parent_job=parent_job,
)
child_job.save()
# Make parent_job wait until its child jobs finish
status, output, errors = parent_job.wait_for_sub_jobs()