# Development tips for plugins

> Techniques for reaching outside Cloud Management Platform (CMP) from plugin code: remote hosts, stored credentials, HTTP calls, and child jobs

---

Site [llms.txt](/llms.txt)

---

## 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

1. Create a [connection info object](/docs/cmp/configure/integrations/connection-info/) and set its protocol to `winrm`.
1. In the CMP CLI (shell_plus), set the transport type. Supported types are `ntlm`, `kerberos`, `credssp`, and `basic`, depending on what the target requires.

```python
from utilities.models import ConnectionInfo

connection_info = ConnectionInfo.objects.get(name='my_connection_info')
connection_info.transport = 'ntlm'
connection_info.save()
```

### Linux servers

1. Create a [connection info object](/docs/cmp/configure/integrations/connection-info/) 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.

```python
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.

```python
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.

```python
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`: `PENDING` when 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:

```python
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()
```

## Related

- [Structure of a plugin](/docs/cmp/use/orchestration/plugins/structure/)
- [Connection info](/docs/cmp/configure/integrations/connection-info/)
- [Use Django ORM](/docs/cmp/use/orchestration/plugins/django-orm/)
