Successful builds not triggering Docker Cloud build trigger (returning cURL 400 Bad request)

I’m trying to set up a deployment pipeline where successful builds on CircleCI triggers an automated Docker Cloud image build. However the trigger, configured in a $DOCKER_CLOUD_TRIGGER variable, returns with an exit code 0 but results in the below error response;

<html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>

The below cURL command is defined in the $DOCKER_CLOUD_TRIGGER variable (in the CircleCI > Environment Variable UI project settings);

curl --request POST --header "Content-Type:application/json" --data '{"build":true}' https://cloud.docker.com/api/build/v1/source/XXX/trigger/XXX/call/

The circle.yml has the deployment option configured as below (BTW, ignore the incorrect indentation showing below, the indentation is properly set in the actual .yml configuration file);

deployment: dockercloud: branch: master commands: - $DOCKER_CLOUD_TRIGGER

:warning: Note that the above curl commands works correctly and triggers an image build on Docker Cloud when run in a local command line or with the online curl tool (www.hurl.it).

As per the related post here (I am unable to trigger the docker hub image build from cirlceCi - #4 by Keertiraj) everything seems correctly configured.

Am I missing anything? Does anyone have a working build trigger with Docker Cloud? Are there any additional cURL options/values that should be included in the command to make this work?

Any help will be deeply appreciated.

Cheers,
Dela.

1 Like

Update

So after more testing, I made some resolved the issue.

####Single quoted & non-quoted header value
The double quotes (") used in the header value was replaced with a single quote ('). This resolved the 400 Bad request error, resulting in the output below. For debugging purposes, the command was refactored to be made as explicit and verbose as possible;

curl --verbose --trace-time --request POST --header 'Content-Type:application/json' --data '{"build":true}' --url https://cloud.docker.com/api/build/v1/source/XXX/trigger/XXX/call/

With the resulting output;

$DOCKER_CLOUD_TRIGGER 00:35:21.012623 * Hostname was NOT found in DNS cache 00:35:21.073610 * Trying 52.70.244.186... 00:35:21.085065 * Connected to cloud.docker.com (52.70.244.186) port 443 (#0) 00:35:21.085832 * successfully set certificate verify locations: 00:35:21.086030 * CAfile: none CApath: /etc/ssl/certs 00:35:21.086385 * SSLv3, TLS handshake, Client hello (1): 00:35:21.097776 * SSLv3, TLS handshake, Server hello (2): 00:35:21.099066 * SSLv3, TLS handshake, CERT (11): 00:35:21.100624 * SSLv3, TLS handshake, Server key exchange (12): 00:35:21.101046 * SSLv3, TLS handshake, Server finished (14): 00:35:21.101857 * SSLv3, TLS handshake, Client key exchange (16): 00:35:21.102055 * SSLv3, TLS change cipher, Client hello (1): 00:35:21.102344 * SSLv3, TLS handshake, Finished (20): 00:35:21.113980 * SSLv3, TLS change cipher, Client hello (1): 00:35:21.114254 * SSLv3, TLS handshake, Finished (20): 00:35:21.114480 * SSL connection using XXX 00:35:21.114665 * Server certificate: 00:35:21.114854 * subject: CN=*.docker.com 00:35:21.115047 * start date: 2017-08-11 00:00:00 GMT 00:35:21.115239 * expire date: 2018-09-11 12:00:00 GMT 00:35:21.115448 * subjectAltName: cloud.docker.com matched 00:35:21.115645 * issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon 00:35:21.115835 * SSL certificate verify ok. 00:35:21.116131 > POST /api/build/v1/source/XXX/trigger/XXX/call/ HTTP/1.1 00:35:21.116131 > User-Agent: curl/7.35.0 00:35:21.116131 > Host: cloud.docker.com 00:35:21.116131 > Accept: */* 00:35:21.116131 > Content-Type:application/json 00:35:21.116131 > Content-Length: 16 00:35:21.116131 > 00:35:21.117232 * upload completely sent off: 16 out of 16 bytes 00:35:21.377429 < HTTP/1.1 202 ACCEPTED 00:35:21.379002 < Date: Wed, 23 Aug 2017 00:35:22 GMT 00:35:21.380704 < Content-Type: application/json 00:35:21.382370 < Content-Length: 448 00:35:21.383817 < Vary: Accept 00:35:21.385858 < X-Content-Type-Options: nosniff 00:35:21.387435 < X-Frame-Options: deny 00:35:21.389177 < X-RateLimit-Limit: 60 00:35:21.390712 < X-RateLimit-Remaining: 59 00:35:21.392407 < X-RateLimit-Reset: 60 00:35:21.393824 < X-XSS-Protection: 1; mode=block 00:35:21.395278 * Server nginx is not blacklisted 00:35:21.397224 < Server: nginx 00:35:21.398757 < Strict-Transport-Security: max-age=31536000 00:35:21.400714 < 00:35:21.402664 * Connection #0 to host cloud.docker.com left intact {"autotests": "OFF", "build_in_farm": true, "build_settings": ["/api/build/v1/setting/XXX/"], "channel": "Stable", "envvars": [], "image": "vieo/pluralsight-docker-ci", "owner": "VieoCo", "provider": "Github", "repo_links": false, "repository": "pluralsight-docker-CI", "resource_uri": "/api/build/v1/source/XXX/", "state": "Success", "uuid": "XXX"}

The same above output is obtained when the header value is passed without the single quotes. The critical thing to note here is that, even though we were now hitting the Docker API endpoint, the JSON data payload which tells the Docker endpoint to start a build wasn’t being properly received, as the below response from the working version of the cURL command wasn’t being returned;

00:25:04.188010 < X-DockerCloud-Action-URI: /api/audit/v1/action/XXX/

####Testing command from within the Build VM (via SSH)
The above cURL command (with and without the header quotes ) were tested in a running build VM using the Rebuild with SSH option. And this was where we identified the main issue.

Typing out the command as is directly in the console worked correctly, as it did on my local machine. However assigning the same command to an environment variable, and then executing the environment variable failed. Echoing out the value of the environment variable ultimately revealed the issue i.e. values with quotations are stripped/modified during assignment to the environment variable.

####:white_check_mark: Working value
So after some adjustments and testing, the final working $DOCKER_CLOUD_TRIGGER environment variable ended up being;

curl --request POST --header Content-Type:application/json --data {"build":true} --url https://cloud.docker.com/api/build/v1/source/XXX/trigger/XXX/call/


:information_source: See this helpful StackExchange answer for a good explanation of quotes handling in Linux/Unix shell/environment variables: What is the significance of single and double quotes in environment variables?