Dynamically register SSH target using Octopus API

Hi everyone,

Currently attempting to register a dynamic SSH target with Octopus through the API. The target will be launched daily under an autoscaling group in AWS, with the idea that once it has registered it can pull down the latest release for a given project in Octopus.

I am attempting to call:

POST /api/machines

{
    "Endpoint": {
        "AccountId": "??????",
        "CommunicationStyle": "Ssh",
        "Host":"10.123.11.123",
        "Port":"22",
        "Thumbprint":"xzy123xzy123xzy123xzy123",
        "Fingerprint": "xzy123xzy123xzy123xzy123",
        "EnvironmentIds": ["Environments-2"],
        "Name":"sshRegistrationTarget",
        "DisplayName":"sshRegistrationTarget",
        "Id":"sshRegistrationTarget",
        "Roles": ["linux"],                                          #Not sure if it's Roles or Role...?
        "Role": "linux"                                               #Not sure if it's Roles or Role...?
    }
}

Have a few questions, but let’s start with this - where do I find my AccountId?

Am I doing this wrong?

Thanks,
Chris

Hi Chris,

Thanks for getting in touch. I had to test this out to figure out the sequence of calls as I didn’t know it off the top of my head. In this scenario, I create a new SSH deploy target in Chrome w/ the network tab open and watched the example requests/responses. In general, you’ll need to create a SSH key pair account or SSH username/password account first. This is the account you mentioned. Then you can add a deployment target/machine and specify the associated data. Example below.

  1. Create SSH username/password account

Post to /api/accounts

Request:

{
    "AccountType":"UsernamePassword",
    "EnvironmentIds":[],
    "Name":"Ubuntu Parallels",
    "Username":"parallels",
    "Password": { "NewValue":"somepassword ... " },
    "TenantIds":[]
}

Response:

{
  "AccountType": "UsernamePassword",
  "Username": "parallels",
  "Password": {
    "HasValue": true,
    "NewValue": null
  },
  "Name": "Ubuntu Parallels",
  "Description": null,
  "EnvironmentIds": [],
  "TenantIds": [],
  "TenantTags": [],
  "Id": "usernamepassword-ubuntu-parallels",
  "LastModifiedOn": "2017-06-09T03:57:15.135+00:00",
  "LastModifiedBy": "admin",
  "Links": {
    "Self": "/api/accounts/usernamepassword-ubuntu-parallels"
  }
}

Response:

  1. Create new SSH deployment target

Post to /api/machines

Request:

{
    "Endpoint":
    {
        "CommunicationStyle":"Ssh",
        "Fingerprint":"...",
        "Host":"192.168.178.31",
        "Port":"22",
        "Uri":"ssh://192.168.178.31:22/",
        "AccountId":"usernamepassword-ubuntu-parallels",
        "AccountType":"UsernamePassword"
    },
        "Status":"Unknown",
        "Name":"192.168.178.31",
        "MachinePolicyId":"MachinePolicies-1",
        "Roles":["web"],
        "EnvironmentIds":["Environments-1"],
        "TenantIds":[]
}

Response:

{
  "Id": "Machines-21",
  "Name": "192.168.178.31",
  "Thumbprint": null,
  "Uri": null,
  "IsDisabled": false,
  "EnvironmentIds": [
    "Environments-1"
  ],
  "Roles": [
    "web"
  ],
  "MachinePolicyId": "MachinePolicies-1",
  "TenantIds": [],
  "TenantTags": [],
  "Status": "Unknown",
  "HealthStatus": "Unknown",
  "HasLatestCalamari": false,
  "StatusSummary": "This machine was recently added. Please perform a health check.",
  "IsInProcess": false,
  "Endpoint": {
    "CommunicationStyle": "Ssh",
    "AccountId": "usernamepassword-ubuntu-parallels",
    "Host": "192.168.178.31",
    "Port": 22,
    "Fingerprint": "...",
    "Uri": "ssh://192.168.178.31:22/",
    "ProxyId": null,
    "Id": null,
    "LastModifiedOn": null,
    "LastModifiedBy": null,
    "Links": {}
  },
  "LastModifiedOn": "2017-06-09T04:13:03.696+00:00",
  "LastModifiedBy": "admin",
  "Links": {
    "Self": "/api/machines/Machines-21",
    "Connection": "/api/machines/Machines-21/connection",
    "TasksTemplate": "/api/machines/Machines-21/tasks{?skip}"
  }
}

Note: I tested this on Octopus 3.14.0 but this should be pretty similar in older versions. I generally explore the Octopus API with Google Chrome and our API documentation wiki.

Hope this helps!

Thanks

Rob

Hi Rob,

Thanks for clearing that up! Will give it a go and report back if I have any problems.

Chris

Works perfectly, thank you! Only thing to note is, I needed to change the account type to “SshKeyPair” since I’m on AWS. But this was easy enough.

Thanks again for your help!

Hi Chris,

That’s great to hear you got it working. Yes, you’re correct that you’d need to update it if you were using SSH keypairs and not username/password as in my example.

Happy deployments!

Thanks

Rob

Just thought I’d update with how I’m doing it for anyone else who might go down this route -

# Define your variables, get account ID etc. etc..
# Then:

echo "Registering instance as machine..."

curl -H "X-Octopus-ApiKey: $apiKey" -H "Content-Type: application/json" -X POST ${octopusUrl}/api/machines -d '{"Endpoint": {"CommunicationStyle":"Ssh", "Fingerprint":"'$fingerprint'", "Host":"'$localIp'", "Port":"22", "Uri":"ssh://'$localIp'/", "AccountId":"'$accountId'", "AccountType":"SshKeyPair"}, "Status":"Unknown", "Name":"'$machineName'", "MachinePolicyId":"MachinePolicies-1", "Roles":["ssh"], "EnvironmentIds":["'$environmentId1'", "'$environmentId2'"], "TenantIds":[]}'

echo -e "Finished registering instance as machine.\nFinding latest release ID..."

#GET LATEST RELEASE
releaseId=$(curl -H "X-Octopus-ApiKey: $apiKey" -H "Content-Type: application/json" -X GET 10.221.11.123/api/channels/channels-277/releases | jq ".Items[].Id" -r)

echo "Release ${releaseId}: triggering deployment..."

#TRIGGER DEPLOYMENT
curl -H "X-Octopus-ApiKey: $apiKey" -H "Content-Type: application/json" -X POST ${octopusUrl}/api/deployments -d '{"ReleaseId":"'$releaseId'", "EnvironmentId":"Environments-1"}'

I was using jq to create a JSON object, then trying to pass that into my curl call. Turned out it was easier just passing it inline with a -d flag.

If you’re on AWS, you can add the above script to your userdata for the instance launch configuration.

Extra bits that might be useful:

# Get Octopus friendly IPv4 of instance
localIp=$(ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}')

# Generate fingerprint
fingerprint=$(ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub | cut -d' ' -f2 | awk '{ print $1}')

Hopefully this is useful to someone!