I am working on downloading a Docker Image on an internet-connected Windows machine that does not have (and cannot have) Docker installed on it, to transfer to an non-internet-connected Linux machine that does have Docker. I'm using git-bash to run download-frozen-image-v2.sh. Everything is working as expected until the script begins to download the final layer of any given image. On the final layer the json file is being returned empty. Through echo statements, I'm able to see that everything is working flawlessly until lines 119-142
jq "$addJson + ." > "$dir/$layerId/json" <<-'EOJSON'
{
"created": "0001-01-01T00:00:00Z",
"container_config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
}
}
EOJSON
Only on the final layer, this code is resulting in an empty json file, which in-turn creates an error in line 173
jq --raw-output "$imageOldConfig + del(.history, .rootfs)" "$dir/$configFile" > "$dir/$imageId/json"
jq: error: syntax error, unexpected '+', expecting $end (Windows cmd shell quoting issues?) at <top-level>, line 1:
+ del(.history, .rootfs)
jq: 1 compile error
Update
Exact steps to replicate
Perform on Windows 10 computer.
1) Install scoop for Windows https://scoop.sh/
2) in Powershell scoop install git curl jq go tar
3) git-bash
4) in git-bash curl -o download-frozen-image-v2.sh https://raw.githubusercontent.com/moby/moby/master/contrib/download-frozen-image-v2.sh
5) bash download-frozen-image-vs.sh ubuntu ubuntu:latest
The above will result in the aforementioned error.
in response to #peak below
The command I'm using is bash download-frozen-image-v2.sh ubuntu ubuntu:latest which should download 5 layers. The first 4 download flawlessly, it is only the last layer that fails. I tried this process for several other images, and it always fails on the final layer.
addJson:
{ id: "ee6b1042efee4fb07d2fe1a5079ce498567e6f5ac849413f0e623d4582da5bc9", parent: "80a2fb00dfe137a28c24fbc39fde656650cd68028d612e6f33912902d887b108" }
dir/configFile:
ubuntu/113a43faa1382a7404681f1b9af2f0d70b182c569aab71db497e33fa59ed87e6.json
dir/configFile contents:
{
"architecture": "amd64",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"ArgsEscaped": true,
"Image": "sha256:c2775c69594daa3ee360d8e7bbca93c65d9c925e89bd731f12515f9bf8382164",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"container": "6713e927cc43b61a4ce3950a69907336ff55047bae9393256e32613a54321c70",
"container_config": {
"Hostname": "6713e927cc43",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/bin/bash\"]"
],
"ArgsEscaped": true,
"Image": "sha256:c2775c69594daa3ee360d8e7bbca93c65d9c925e89bd731f12515f9bf8382164",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"created": "2018-06-05T21:20:54.310450149Z",
"docker_version": "17.06.2-ce",
"history": [
{
"created": "2018-06-05T21:20:51.286433694Z",
"created_by": "/bin/sh -c #(nop) ADD file:28c0771e44ff530dba3f237024acc38e8ec9293d60f0e44c8c78536c12f13a0b in / "
},
{
"created": "2018-06-05T21:20:52.045074543Z",
"created_by": "/bin/sh -c set -xe \t\t&& echo '#!/bin/sh' > /usr/sbin/policy-rc.d \t&& echo 'exit 101' >> /usr/sbin/policy-rc.d \t&& chmod +x /usr/sbin/policy-rc.d \t\t&& dpkg-divert --local --rename --add /sbin/initctl \t&& cp -a /usr/sbin/policy-rc.d /sbin/initctl \t&& sed -i 's/^exit.*/exit 0/' /sbin/initctl \t\t&& echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \t\t&& echo 'DPkg::Post-Invoke { \"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\"; };' > /etc/apt/apt.conf.d/docker-clean \t&& echo 'APT::Update::Post-Invoke { \"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\"; };' >> /etc/apt/apt.conf.d/docker-clean \t&& echo 'Dir::Cache::pkgcache \"\"; Dir::Cache::srcpkgcache \"\";' >> /etc/apt/apt.conf.d/docker-clean \t\t&& echo 'Acquire::Languages \"none\";' > /etc/apt/apt.conf.d/docker-no-languages \t\t&& echo 'Acquire::GzipIndexes \"true\"; Acquire::CompressionTypes::Order:: \"gz\";' > /etc/apt/apt.conf.d/docker-gzip-indexes \t\t&& echo 'Apt::AutoRemove::SuggestsImportant \"false\";' > /etc/apt/apt.conf.d/docker-autoremove-suggests"
},
{
"created": "2018-06-05T21:20:52.712120056Z",
"created_by": "/bin/sh -c rm -rf /var/lib/apt/lists/*"
},
{
"created": "2018-06-05T21:20:53.405342638Z",
"created_by": "/bin/sh -c sed -i 's/^#\\s*\\(deb.*universe\\)$/\\1/g' /etc/apt/sources.list"
},
{
"created": "2018-06-05T21:20:54.091704323Z",
"created_by": "/bin/sh -c mkdir -p /run/systemd && echo 'docker' > /run/systemd/container"
},
{
"created": "2018-06-05T21:20:54.310450149Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/bash\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:db9476e6d963ed2b6042abef1c354223148cdcdbd6c7416c71a019ebcaea0edb",
"sha256:3a89e0d8654e098e949764b1cb23018e27f299b0931c5fd41c207d610ff356c4",
"sha256:904d60939c360b5f528b886c1b534855a008f9a7fd411d4977e09aa7de74c834",
"sha256:a20a262b87bd8a00717f3b30c001bcdaf0fd85d049e6d10500597caa29c013c5",
"sha256:b6f13d447e00fba3b9bd10c1e5c6697e913462f44aa24af349bfaea2054e32f4"
]
}
}
Any help in figuring out what is occurring here would be greatly appreciated.
Thank you.
I can't tell you why this happens but it appears to be a problem with how jq parses the input file. It's segfaulting when reading the file. It's a known issue in the windows builds where the problem is triggered by the length of the paths to the files.
Fortunately, there is a way around this issue by modifying the script to go against all conventional wisdom and cat the file to jq.
The script isn't utilizing jq very well and builds some of the json manually so some additional fixes would be needed. It will have errors regarding INVALID_CHARACTER when parsing. It's probably a manifestation of this issue since the script is manually building a lot of the jq programs.
I put up a gist with the updated file that at least doesn't error out, check to see if it works as expected.
Changes start at line 172 and 342.
The way it builds the manifest is just messy. I've cleaned it up a bit removing all the string interpolations instead passing all parameters in as arguments to jq.
# munge the top layer image manifest to have the appropriate image configuration for older daemons
local imageOldConfig="$(cat "$dir/$imageId/json" | jq --raw-output --compact-output '{ id: .id } + if .parent then { parent: .parent } else {} end')"
cat "$dir/$configFile" | jq --raw-output "$imageOldConfig + del(.history, .rootfs)" > "$dir/$imageId/json"
local manifestJsonEntry="$(
jq --raw-output --compact-output -n \
--arg configFile "$configFile" \
--arg repoTags "${image#library\/}:$tag" \
--argjson layers "$(IFS=$'\n'; jq --arg a "${layerFiles[*]}" -n '$a | split("\n")')" \
'{
Config: $configFile,
RepoTags: [ $repoTags ],
Layers: $layers
}'
)"
(1) I have verified that using bash, the sequence:
addJson='{ id: "ee6b1042efee4fb07d2fe1a5079ce498567e6f5ac849413f0e623d4582da5bc9",
parent: "80a2fb00dfe137a28c24fbc39fde656650cd68028d612e6f33912902d887b108" }'
jq "$addJson + ." configFile > layerId.json
succeeds, where configFile has the contents shown in the updated question.
(2) Similarly, I have verified that the following also succeeds:
imageOldConfig="$(jq --raw-output --compact-output '{ id: .id } + if .parent then { parent: .parent } else {} end' layerId.json)"
jq --raw-output "$imageOldConfig + del(.history, .rootfs)" <<-'EOJSON'
<JSON as in the question>
EOJSON
where <JSON as in the question> stands for the JSON shown in the question.
(3) In general, it is not a good idea to pass shell $-variables into jq programs by shell string interpolation.
For example, rather than writing:
jq --raw-output "$imageOldConfig + del(.history, .rootfs)"
it would be much better to write something like:
jq --raw-output --argjson imageOldConfig "$imageOldConfig" '
$imageOldConfig + del(.history, .rootfs)'
Related
I have encountered an issue during provisioning with HashiCorp Packer for virtualbox-iso on Alpine Linux v3.16.
Provisioning script runs OK, and it logs that build has finished, however when I open the outputted ovf file in VirtualBox moved files and docker are not present.
I would be grateful for any advice.
I run packer build packer-virtualbox-alpine-governator.json
packer-virtualbox-alpine-governator.json file:
{
"variables": {
"password": "packer"
},
"builders": [
{
"type": "virtualbox-iso",
"memory": 8192,
"guest_os_type": "Other_64",
"iso_url": "https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/x86_64/alpine-standard-3.16.0-x86_64.iso",
"iso_checksum": "file:https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/x86_64/alpine-standard-3.16.0-x86_64.iso.sha256",
"ssh_username": "root",
"ssh_password": "{{user `password`}}",
"shutdown_command": "poweroff",
"hard_drive_interface": "sata",
"boot_command": [
"root<enter><wait>",
"setup-alpine<enter><wait>us<enter><wait>us<enter><wait><enter><wait><enter><wait><enter><wait><enter><wait5>{{user `password`}}<enter><wait>{{user `password`}}<enter><wait><enter><wait><enter><wait><enter><wait15><enter><wait>openssh<enter><wait>openssh-full<enter><wait5>test123<enter><wait5>test123<enter><wait><enter><wait><enter><wait>sda<enter><wait>sys<enter><wait>y<enter><wait30>",
"echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config<enter><wait>",
"/etc/init.d/sshd restart<enter><wait5>"
]
}
],
"provisioners": [
{
"type": "shell",
"inline": ["mkdir -p /opt/site/governator"]
},
{
"type": "file",
"source": "files/docker-compose.yaml",
"destination": "/opt/site/"
},
{
"type": "file",
"source": "files/governator.conf",
"destination": "/opt/site/governator/"
},
{
"type": "shell",
"scripts": [
"scripts/alpine/install-docker-on-alpine.sh"
]
}
]
}
./scritps/alpine/install-docker-on-alpine.sh
#! /bin/ash
cat > /etc/apk/repositories << EOF; $(echo)
https://dl-cdn.alpinelinux.org/alpine/v$(cut -d'.' -f1,2 /etc/alpine-release)/main/
https://dl-cdn.alpinelinux.org/alpine/v$(cut -d'.' -f1,2 /etc/alpine-release)/community/
https://dl-cdn.alpinelinux.org/alpine/edge/testing/
EOF
apk update
apk add docker
addgroup $USER docker
rc-update add docker boot
service docker start
apk add docker-compose
sync
I am trying out Windows Terminal. I use bash and want the Windows Terminal Tab title to remain as cwd (which is initially set by bash) instead of changing since while using multiple tabs they become indistinguishable. If I run say npm run start in bash directly, the title (in title bar) remains as cwd but if I try to use it via Windows Terminal the tab title changes to npm which I don't want.
My .bashrc
if test -f /etc/profile.d/git-sdk.sh
then
TITLEPREFIX=SDK-${MSYSTEM#MINGW}
else
TITLEPREFIX=$MSYSTEM
fi
if test -f ~/.config/git/git-prompt.sh
then
. ~/.config/git/git-prompt.sh
else
# PS1='\[\033]0;$TITLEPREFIX:$PWD\007\]' # set window title
# PS1='\[\e]0;\W\a\]\[\033]0;$PWD\007\]' # set window title (full path)
PS1='\[\e]0;\W\a\]' # set window title (only directory name)
PS1="$PS1"'\n' # new line
PS1="$PS1"'\[\033[32m\]' # change to green
PS1="$PS1"'\u ' # user#host<space>
# PS1="$PS1"'\[\033[35m\]' # change to purple
# PS1="$PS1"'$MSYSTEM ' # show MSYSTEM
PS1="$PS1"'\[\033[33m\]' # change to brownish yellow
PS1="$PS1"'\w' # current working directory
if test -z "$WINELOADERNOEXEC"
then
GIT_EXEC_PATH="$(git --exec-path 2>/dev/null)"
COMPLETION_PATH="${GIT_EXEC_PATH%/libexec/git-core}"
COMPLETION_PATH="${COMPLETION_PATH%/lib/git-core}"
COMPLETION_PATH="$COMPLETION_PATH/share/git/completion"
if test -f "$COMPLETION_PATH/git-prompt.sh"
then
. "$COMPLETION_PATH/git-completion.bash"
. "$COMPLETION_PATH/git-prompt.sh"
PS1="$PS1"'\[\033[36m\]' # change color to cyan
PS1="$PS1"'`__git_ps1`' # bash function
fi
fi
PS1="$PS1"'\[\033[0m\]' # change color
PS1="$PS1"'\n' # new line
PS1="$PS1"'$ ' # prompt: always $
fi
MSYS2_PS1="$PS1" # for detection by MSYS2 SDK's bash.basrc
# Evaluate all user-specific Bash completion scripts (if any)
if test -z "$WINELOADERNOEXEC"
then
for c in "$HOME"/bash_completion.d/*.bash
do
# Handle absence of any scripts (or the folder) gracefully
test ! -f "$c" ||
. "$c"
done
fi
export PS1='${debian_chroot:+($debian_chroot)}\[\e]0;\W\a\]\[\033[01;32m\]\u \[\033[00m\]\[\033[01;00m\]\w\n$ '
# echo -ne '\033]0;New Title\a'
My Windows Terminal settings.json
{
"$schema": "https://aka.ms/terminal-profiles-schema",
"defaultProfile": "{00000000-0000-0000-ba54-000000000002}",
"copyOnSelect": false,
"copyFormatting": false,
"profiles": {
"defaults": {
"fontSize": 10
},
"list": [
{
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"hidden": false
},
{
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "Command Prompt",
"commandline": "cmd.exe",
"hidden": false
},
{
"guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
"hidden": false,
"name": "Azure Cloud Shell",
"source": "Windows.Terminal.Azure"
},
{
"guid": "{00000000-0000-0000-ba54-000000000002}",
"commandline": "%PROGRAMFILES%/git/usr/bin/bash.exe -i -l",
"icon": "%PROGRAMFILES%/Git/mingw64/share/git/git-for-windows.ico",
"name": "Bash",
"startingDirectory": "%USERPROFILE%"
}
]
},
"schemes": [],
"actions": [
{ "command": { "action": "copy", "singleLine": false }, "keys": "ctrl+c" },
{ "command": "paste", "keys": "ctrl+v" },
{ "command": "find", "keys": "ctrl+shift+f" },
{
"command": {
"action": "splitPane",
"split": "auto",
"splitMode": "duplicate"
},
"keys": "alt+shift+d"
}
]
}
How do I achieve this?
windows terminal has two tag to change this
"tabTitle": "yourtitle",
"suppressApplicationTitle": true
so in your case, maybe you can write like this
{
"guid": "{00000000-0000-0000-ba54-000000000002}",
"commandline": "%PROGRAMFILES%/git/usr/bin/bash.exe -i -l",
"icon": "%PROGRAMFILES%/Git/mingw64/share/git/git-for-windows.ico",
"name": "Bash",
"startingDirectory": "%USERPROFILE%",
"tabTitle": "cwd",
"suppressApplicationTitle": true
}
I know how to create a repo in BitBucket by doing this.
Let email = john#outlook.com, and password 123
curl -k -X POST --user john#outlook.com:123 "https://api.bitbucket.org/1.0/repositories" -d "name=test"
But how would one check if a repo exist in BitBucket programmatically ?
Here is what I get for a curl call to a public, private and non-existing repos:
Private (Status code 403):
> curl -k -X GET https://api.bitbucket.org/1.0/repositories/padawin/some-private-repo
Forbidden
Non existing (Status code 404):
> curl -k -X GET https://api.bitbucket.org/1.0/repositories/padawin/travels1
{"type": "error", "error": {"message": "Repository padawin/travels1 not found"}}
Public (Status code 200):
> curl -k -X GET https://api.bitbucket.org/1.0/repositories/padawin/travels
{"scm": "git", "has_wiki": false, "last_updated": "2015-08-02T14:09:42.134", "no_forks": false, "forks_count": 0, "created_on": "2014-06-08T23:48:28.483", "owner": "padawin", "logo": "https://bytebucket.org/ravatar/%7Bb56f8d55-4821-4c89-abbc-7c1838fb68a3%7D?ts=default", "email_mailinglist": "", "is_mq": false, "size": 1194864, "read_only": false, "fork_of": null, "mq_of": null, "followers_count": 1, "state": "available", "utc_created_on": "2014-06-08 21:48:28+00:00", "website": "", "description": "", "has_issues": false, "is_fork": false, "slug": "travels", "is_private": false, "name": "travels", "language": "", "utc_last_updated": "2015-08-02 12:09:42+00:00", "no_public_forks": false, "creator": null, "resource_uri": "/api/1.0/repositories/padawin/travels"}
You can use the status code, given that the body is not always a valid json (Forbidden would have to be "Forbidden" to be a valid JSON).
Using the 2.0 API, I check in this way:
if curl -s -f -o /dev/null -u "${USERNAME}:${APP_PASSWORD}" "https://api.bitbucket.org/2.0/repositories/${USERNAME}/${REPONAME}"; then
echo "Repo exists in Bitbucket."
else
echo "Repo either does not exist or is inaccessible in Bitbucket."
Access is required to the repository:read scope. Note that access to the repository:admin scope is insufficient and irrelevant for this check.
I'm working on generating a new JSON payload to update Consul with a MSSQL database service location.
When I call jq like this:
mssql_svc_ip=$(kubectl get svc/mssql-linux -o 'jsonpath={.spec.clusterIP}')
mssql_svc_port=$(kubectl get svc/mssql-linux -o 'jsonpath={.spec.ports[0].port}')
jq -n -r --arg MSSQL_IP $mssql_svc_ip --arg MSSQL_PORT $mssql_svc_port '{
"Datacenter": "dev",
"Node": "database",
"Address": $MSSQL_IP,
"Service": {
"Service": "mssql-dev",
"Port": $MSSQL_PORT
}
}'
It produces the proper structure:
{
"Datacenter": "dev",
"Node": "database",
"Address": "10.43.192.146",
"Service": {
"Service": "mssql-dev",
"Port": "1433"
}
}
I need to convert the Service.Port field from a string to an integer as that's what the Consul API requires. I can do that with tonumber, like this:
mssql_svc_ip=$(kubectl get svc/mssql-linux -o 'jsonpath={.spec.clusterIP}')
mssql_svc_port=$(kubectl get svc/mssql-linux -o 'jsonpath={.spec.ports[0].port}')
jq -n -r --arg MSSQL_IP $mssql_svc_ip --arg MSSQL_PORT $mssql_svc_port '{
"Datacenter": "dev",
"Node": "database",
"Address": $MSSQL_IP,
"Service": {
"Service": "mssql-dev",
"Port": tonumber($MSSQL_PORT)
}
}'
However, when I try and convert the $MSSQL_PORT variable to a number, I get this error:
jq: error: tonumber/1 is not defined at <top-level>, line 7:
"Port": tonumber($MSSQL_PORT)
jq: 1 compile error
At first I thought it was an assignment error and the variables weren't being passes as arguments properly, but I've tried a couple iterations and I still get the same error. What am I doing incorrectly?
I think you are misusing the tonumber filter. Based on the documentation it looks like the syntax would be something like:
jq -n -r --arg MSSQL_IP "$mssql_svc_ip" --arg MSSQL_PORT "$mssql_svc_port" '{
"Datacenter": "dev",
"Node": "database",
"Address": $MSSQL_IP,
"Service": {
"Service": "mssql-dev",
"Port": ($MSSQL_PORT|tonumber)
}
}'
And indeed, if $msssql_svc_ip is 10.43.192.146 and $mssql_svc_port is
1433, that gets me:
{
"Datacenter": "dev",
"Node": "database",
"Address": "10.43.192.146",
"Service": {
"Service": "mssql-dev",
"Port": 1433
}
}
Looks like you need to pass the number in with --argjson instead of --arg:
$ jq -n -r --argjson foo 12 '{"foo":$foo}'
{
"foo": 12
}
This seems simpler than using tonumber
I am playing around with hazelcast, using aws cloudformation and ansible to spin up a cluster of two hazelcast nodes + a separate mancenter.
All documentation on the mancenter implies everything must be done manually by a user in a browser. However this is not ideal as we will have many environments and have a hardened ami provided to us every few weeks which we must update existing environment to.
What I am trying to do is create an ansible role that automatically creates the first admin user, and then adds the enterprise license into the mancenter.
I have successfully scripted the user creation (just http for now, baby steps)
- name: Check for first user
uri:
url: "http://{{ hazelcastmanagement_dns }}:8080/mancenter/user.do?operation=anyUser&_=1480397059541"
method: GET
return_content: no
register: anyuser
until: anyuser.json["anyUser"] is defined
retries: 10
delay: 5
- name: Register Admin user
uri:
url: "http://{{ hazelcastmanagement_dns }}:8080/mancenter/user.do?operation=signUp&username={{ hazelcastmanagement_user }}&password={{ hazelcastmanagement_password }}&confirmpassword={{ hazelcastmanagement_password }}&email={{ hazelcastmanagement_email }}&_=1479951949840"
method: GET
return_content: no
register: result
until: result.json["success"] is defined
retries: 10
delay: 5
when: anyuser.json["anyUser"] == "false"
However I am having trouble successfully orchestrating the update license call.
In a browser, certain calls return the JSESSION ID, and HTTP 200's. When trying to emulate this in ansible however, I am always getting a 302, redirect to the login page.
I have pasted the tasks below that I am attempting.
These task examples do not contain many headers, however I have tried emulating every single header that a browser sends previously but had the same result.
- name: Call to update license unauthorized (returns set_cookie)
uri:
url: "http://{{ hazelcastmanagement_dns }}:8080/mancenter/main.do"
method: POST
return_content: yes
body: "operation=savelicense_getLicenceInfo&key={{ hazelcast_license }} "
status_code: 302
register: cookie
- name: Login (302 ok because browser mirrors this result)
uri:
url: "http://{{ hazelcastmanagement_dns }}:8080/mancenter/j_spring_security_check"
method: POST
body: "j_username={{ hazelcastmanagement_user }}&j_password={{ hazelcastmanagement_password }}"
return_content: yes
status_code: 302
HEADER_Cookie: "{{cookie.set_cookie}}"
- name: Call to update license authorized
uri:
url: "http://{{ hazelcastmanagement_dns }}:8080/mancenter/main.do"
method: POST
return_content: yes
body: "operation=savelicense_getLicenceInfo&key={{ hazelcast_license }}"
HEADER_Cookie: "{{cookie.set_cookie}}"
My ansible task logs are below, -vvvv
Hoping someone else has looked into this previously, could not find any questions related to it elsewhere however.
Ansible Log Output:
TASK [hazelcastmanagement_launch : Call to update license authorized] **********
task path: /app/esg/ansible/roles/hazelcastmanagement_launch/tasks/launch.yml:5
ESTABLISH LOCAL CONNECTION FOR USER: root
hazelcast EXEC ( umask 22 && mkdir -p "$( echo /tmp/ansible-tmp-1480399947.07-7077332634698 )" && echo "$( echo /tmp/ansible-tmp-1480399947.07-7077332634698 )" )
hazelcast PUT /tmp/tmpBbuVj0 TO /tmp/ansible-tmp-1480399947.07-7077332634698/uri
hazelcast EXEC chmod a+r /tmp/ansible-tmp-1480399947.07-7077332634698/uri
hazelcast EXEC /bin/sh -c 'sudo -H -S -n -u esg /bin/sh -c '"'"'echo BECOME-SUCCESS-lemxlebthsblahblahblahcevqzkafjdo; LANG=en_US.UTF-8 HTTP_PROXY=proxy.com LC_MESSAGES=en_US.UTF-8 HTTPS_PROXY=proxy.com no_proxy=proxy.com http_proxy=proxy.com https_proxy=proxy.com NO_PROXY=proxy.com LC_ALL=en_US.UTF-8 /usr/bin/python /tmp/ansible-tmp-1480399947.07-7077332634698/uri'"'"''
hazelcast EXEC rm -f -r /tmp/ansible-tmp-1480399947.07-7077332634698/ > /dev/null 2>&1
ok: [hazelcast] => {"changed": false, "content": "", "content_length": "0", "expires": "Thu, 01 Jan 1970 00:00:00 GMT", "invocation": {"module_args": {"backup": null, "body": "operation=savelicense_getLicenceInfo&key=ENTERPRISELicense12341234123412341234123412341234", "body_format": "raw", "content": null, "creates": null, "delimiter": null, "dest": null, "directory_mode": null, "follow": false, "follow_redirects": "safe", "force": null, "force_basic_auth": false, "group": null, "method": "POST", "mode": null, "owner": null, "password": null, "regexp": null, "remote_src": null, "removes": null, "return_content": true, "selevel": null, "serole": null, "setype": null, "seuser": null, "src": null, "status_code": ["302"], "timeout": 30, "url": "http://internal-esg-aws.elb.amazonaws.com:8080/mancenter/main.do", "user": null, "validate_certs": true}, "module_name": "uri"}, "location": "http://internal-esg-aws.elb.amazonaws.com:8080/mancenter/login.jsp;jsessionid=dq0hzdvm2xm91r4h6eyef1l48", "redirected": false, "server": "Jetty(8.y.z-SNAPSHOT)", "set_cookie": "JSESSIONID=dq0hzdvm2xm91r4h6eyef1l48;Path=/mancenter;HttpOnly", "status": 302}
TASK [hazelcastmanagement_launch : Login] **************************************
task path: /app/app/ansible/roles/hazelcastmanagement_launch/tasks/launch.yml:14
ESTABLISH LOCAL CONNECTION FOR USER: root
hazelcast EXEC ( umask 22 && mkdir -p "$( echo /tmp/ansible-tmp-1480399947.23-71435275964843 )" && echo "$( echo /tmp/ansible-tmp-1480399947.23-71435275964843 )" )
hazelcast PUT /tmp/tmpKhOI1y TO /tmp/ansible-tmp-1480399947.23-71435275964843/uri
hazelcast EXEC chmod a+r /tmp/ansible-tmp-1480399947.23-71435275964843/uri
hazelcast EXEC /bin/sh -c 'sudo -H -S -n -u app /bin/sh -c '"'"'echo BECOME-SUCCESS-rfxrchqnblahblahblahhvryauidnf; LANG=en_US.UTF-8 HTTP_PROXY=proxy.com8 LC_MESSAGES=en_US.UTF-8 HTTPS_PROXY=proxy.com no_proxy=proxy.com http_proxy=proxy.com NO_PROXY=proxy.com LC_ALL=en_US.UTF-8 /usr/bin/python /tmp/ansible-tmp-1480399947.23-71435275964843/uri'"'"''
hazelcast EXEC rm -f -r /tmp/ansible-tmp-1480399947.23-71435275964843/ > /dev/null 2>&1
ok: [hazelcast] => {"changed": false, "content": "", "content_length": "0", "invocation": {"module_args": {"HEADER_Cookie": "JSESSIONID=dq0hzdvm2xm91r4h6eyef1l48;Path=/mancenter;HttpOnly", "backup": null, "body": "j_username=admin&j_password=admin1", "body_format": "raw", "content": null, "creates": null, "delimiter": null, "dest": null, "directory_mode": null, "follow": false, "follow_redirects": "safe", "force": null, "force_basic_auth": false, "group": null, "method": "POST", "mode": null, "owner": null, "password": null, "regexp": null, "remote_src": null, "removes": null, "return_content": true, "selevel": null, "serole": null, "setype": null, "seuser": null, "src": null, "status_code": ["302"], "timeout": 30, "url": "http://internal-aws.elb.amazonaws.com:8080/mancenter/j_spring_security_check", "user": null, "validate_certs": true}, "module_name": "uri"}, "location": "http://internal-aws.elb.amazonaws.com:8080/mancenter/login.jsp?login_error=true", "redirected": false, "server": "Jetty(8.y.z-SNAPSHOT)", "status": 302}
TASK [hazelcastmanagement_launch : Call to update license authorized] **********
task path: /app/app/ansible/roles/hazelcastmanagement_launch/tasks/launch.yml:23
ESTABLISH LOCAL CONNECTION FOR USER: root
hazelcast EXEC ( umask 22 && mkdir -p "$( echo /tmp/ansible-tmp-1480399947.38-137956022601151 )" && echo "$( echo /tmp/ansible-tmp-1480399947.38-137956022601151 )" )
hazelcast PUT /tmp/tmpAbC8uL TO /tmp/ansible-tmp-1480399947.38-137956022601151/uri
hazelcast EXEC chmod a+r /tmp/ansible-tmp-1480399947.38-137956022601151/uri
hazelcast EXEC /bin/sh -c 'sudo -H -S -n -u app /bin/sh -c '"'"'echo BECOME-SUCCESS-cciaazzdblahblahblahdufmpuhe; LANG=en_US.UTF-8 HTTP_PROXY=proxy.com LC_MESSAGES=en_US.UTF-8 HTTPS_PROXY=proxy.com no_proxy=proxy.com http_proxy=proxy.com https_proxy=proxy.com NO_PROXY=proxy.comLC_ALL=en_US.UTF-8 /usr/bin/python /tmp/ansible-tmp-1480399947.38-137956022601151/uri'"'"''
hazelcast EXEC rm -f -r /tmp/ansible-tmp-1480399947.38-137956022601151/ > /dev/null 2>&1
fatal: [hazelcast]: FAILED! => {"changed": false, "content": "", "content_length": "0", "failed": true, "invocation": {"module_args": {"HEADER_Cookie": "JSESSIONID=dq0hzdvm2xm91r4h6eyef1l48;Path=/mancenter;HttpOnly", "backup": null, "body": "operation=savelicense_getLicenceInfo&key=ENTERPRISELicense123412341234123412341234123412341234", "body_format": "raw", "content": null, "creates": null, "delimiter": null, "dest": null, "directory_mode": null, "follow": false, "follow_redirects": "safe", "force": null, "force_basic_auth": false, "group": null, "method": "POST", "mode": null, "owner": null, "password": null, "regexp": null, "remote_src": null, "removes": null, "return_content": true, "selevel": null, "serole": null, "setype": null, "seuser": null, "src": null, "status_code": [200], "timeout": 30, "url": "http://internal-aws.elb.amazonaws.com:8080/mancenter/main.do", "user": null, "validate_certs": true}, "module_name": "uri"}, "location": "http://internal-aws.elb.amazonaws.com:8080/mancenter/login.jsp", "msg": "Status code was not [200]", "redirected": false, "server": "Jetty(8.y.z-SNAPSHOT)", "status": 302}
EDIT:
Thanks for that solution emre. Using curl was the way to go.
I tried a few more times with the uri ansible module. But no dice... must be something under the hood going on.
Since your curl's hit the nail on the head, I just wrapped this in the ansible command module instead of using the uri module to construct the calls.
I chdir to /tmp to ensure I have write access for the cookie file.
- name: Login to management
shell: "curl -X POST http://{{ hazelcastmanagement_dns }}:8080/mancenter/j_spring_security_check -d "j_username={{ hazelcastmanagement_user}}" -d "j_password={{ hazelcastmanagement_password }}" -c cookies.file
args:
chdir: /tmp
- name: Login to management
shell: "curl -H "Content-Type: application/x-www-form-urlencoded" -X POST http://{{ hazelcastmanagement_dns }}:8080/mancenter/main.do?operation=savelicense -d 'key={{ hazelcast_licence }}' -b cookies.file
args:
chdir: /tmp
I don't know about Ansible, but using cUrl you can log in and set the license key as follows:
curl -X POST http://localhost:8083/mancenter/j_spring_security_check -d "j_username=emre" -d "j_password=Password1" -c cookies.file
curl -H "Content-Type: application/x-www-form-urlencoded" -X POST http://localhost:8083/mancenter/main.do?operation=savelicense -d 'key=aaaa' -b cookies.file
Note that you need to log in with an admin user and the license key you provide needs to be correct for the server to return 200.
Edit:
With Hazelcast Management Center version 3.9.3, a new system property to configure the license was introduced. See the release notes for version 3.9.3 and the relevant section on the latest reference manual for details.