ansible / ansible-container

DEPRECATED -- Ansible Container was a tool to build Docker images and orchestrate containers using only Ansible playbooks.
GNU Lesser General Public License v3.0
2.19k stars 394 forks source link

conductor.environment variables cannot be jinja expressions #713

Open shalomb opened 7 years ago

shalomb commented 7 years ago
ISSUE TYPE
container.yml
settings:
  conductor_base:      'debian:latest'
  conductor:
    environment:
      - http_proxy={{         ac_environment.http_proxy }}
      - https_proxy={{        ac_environment.https_proxy }}
      - ftp_proxy={{          ac_environment.http_proxy }}
      - no_proxy={{           ac_environment.no_proxy }}
  # vars_file:
  # vault_files: []
  # vault_password_file:

services:
  web:
    from: '{{ services.web.from }}'
    environment:
      - http_proxy={{         ac_environment.http_proxy }}
      - https_proxy={{        ac_environment.https_proxy }}
      - ftp_proxy={{          ac_environment.http_proxy }}
      - no_proxy={{           ac_environment.no_proxy }}
    roles:
      - ansible-decktape
...
$ less env.yml
---

ac_environment:
  http_proxy:  'http://xxx.xxx.xxx.xxx:3128/'
  https_proxy: 'http://xxx.xxx.xxx.xxx:3128/'
  ftp_proxy:   'http://xxx.xxx.xxx.xxx:3128/'
  no_proxy:    'localhost,127.0.0.1,localaddress,.localdomain.com,169.254.169.254'
...
OS / ENVIRONMENT
Ansible Container, version 0.9.2rc0
Linux, sbhooshi-runner2, 4.4.0-28-generic, #47-Ubuntu SMP Fri Jun 24 10:09:13 UTC 2016, x86_64
2.7.12 (default, Nov 19 2016, 06:48:10) 
[GCC 5.4.0 20160609] /usr/bin/python
{
  "ContainersPaused": 0, 
  "Labels": null, 
  "CgroupDriver": "cgroupfs", 
  "ContainersRunning": 0, 
  "ContainerdCommit": {
    "Expected": "9048e5e50717ea4497b757314bad98ea3763c145", 
    "ID": "9048e5e50717ea4497b757314bad98ea3763c145"
  }, 
  "InitBinary": "docker-init", 
  "NGoroutines": 23, 
  "Swarm": {
    "ControlAvailable": false, 
    "NodeID": "", 
    "Error": "", 
    "RemoteManagers": null, 
    "LocalNodeState": "inactive", 
    "NodeAddr": ""
  }, 
  "LoggingDriver": "json-file", 
  "OSType": "linux", 
  "HttpProxy": "http://proxy.hu.in.pan-net.eu:3128/", 
  "Runtimes": {
    "runc": {
      "path": "docker-runc"
    }
  }, 
  "DriverStatus": [
    [
      "Backing Filesystem", 
      "extfs"
    ], 
    [
      "Supports d_type", 
      "true"
    ], 
    [
      "Native Overlay Diff", 
      "false"
    ]
  ], 
  "OperatingSystem": "Ubuntu 16.04 LTS", 
  "Containers": 0, 
  "HttpsProxy": "http://proxy.hu.in.pan-net.eu:3128/", 
  "BridgeNfIp6tables": true, 
  "MemTotal": 4143755264, 
  "SecurityOptions": [
    "name=apparmor", 
    "name=seccomp,profile=default"
  ], 
  "Driver": "overlay2", 
  "IndexServerAddress": "https://index.docker.io/v1/", 
  "ClusterStore": "", 
  "InitCommit": {
    "Expected": "949e6fa", 
    "ID": "949e6fa"
  }, 
  "Isolation": "", 
  "SystemStatus": null, 
  "OomKillDisable": true, 
  "ClusterAdvertise": "", 
  "SystemTime": "2017-08-22T13:06:47.622922235Z", 
  "Name": "sbhooshi-runner2", 
  "CPUSet": true, 
  "RegistryConfig": {
    "InsecureRegistryCIDRs": [
      "127.0.0.0/8"
    ], 
    "IndexConfigs": {
      "docker.io": {
        "Official": true, 
        "Name": "docker.io", 
        "Secure": true, 
        "Mirrors": []
      }
    }, 
    "Mirrors": []
  }, 
  "DefaultRuntime": "runc", 
  "ContainersStopped": 0, 
  "NCPU": 2, 
  "NFd": 17, 
  "Architecture": "x86_64", 
  "KernelMemory": true, 
  "CpuCfsQuota": true, 
  "Debug": false, 
  "ID": "TOK7:VLCZ:6KDK:4X23:HJ3P:MGCV:ZBVN:P6FO:RBLN:WSTO:FPYZ:VCET", 
  "IPv4Forwarding": true, 
  "KernelVersion": "4.4.0-28-generic", 
  "BridgeNfIptables": true, 
  "NoProxy": "localhost,127.0.0.1,localaddress,.localdomain.com,169.254.169.254", 
  "LiveRestoreEnabled": false, 
  "ServerVersion": "17.05.0-ce", 
  "CpuCfsPeriod": true, 
  "ExperimentalBuild": false, 
  "MemoryLimit": true, 
  "SwapLimit": false, 
  "Plugins": {
    "Volume": [
      "local"
    ], 
    "Network": [
      "bridge", 
      "host", 
      "macvlan", 
      "null", 
      "overlay"
    ], 
    "Authorization": []
  }, 
  "Images": 52, 
  "DockerRootDir": "/var/lib/docker", 
  "NEventsListener": 0, 
  "CPUShares": true, 
  "RuncCommit": {
    "Expected": "9c2d8d184e5da67c95d601382adf14862e4f2228", 
    "ID": "9c2d8d184e5da67c95d601382adf14862e4f2228"
  }
}
{
  "KernelVersion": "4.4.0-28-generic", 
  "Arch": "amd64", 
  "BuildTime": "2017-05-04T22:10:54.638119411+00:00", 
  "ApiVersion": "1.29", 
  "Version": "17.05.0-ce", 
  "MinAPIVersion": "1.12", 
  "GitCommit": "89658be", 
  "Os": "linux", 
  "GoVersion": "go1.7.5"
}
SUMMARY
STEPS TO REPRODUCE

The settings.conductor.environment if defined as jinja variables (so these can be set and derived from a --vars-files) will fail with an exception like the following

$ ansible-container --vars-files env.yml build

Building Docker Engine context...
Starting Docker build of Ansible Container Conductor image (please be patient)...
ERROR   Unknown exception
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/container/cli.py", line 291, in __call__
    getattr(core, u'hostcmd_{}'.format(args.subcommand))(**vars(args))
  File "/usr/local/lib/python2.7/dist-packages/container/__init__.py", line 28, in __wrapped__
    return fn(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/container/core.py", line 160, in hostcmd_build
    environment=env_vars
  File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 87, in __wrapped__
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/container/__init__.py", line 28, in __wrapped__
    return fn(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 926, in build_conductor_image
    nocache=not cache)
  File "/usr/local/lib/python2.7/dist-packages/docker/models/images.py", line 173, in build
    for chunk in json_stream(resp):
  File "/usr/local/lib/python2.7/dist-packages/docker/utils/json_stream.py", line 66, in split_buffer
    for data in stream_as_text(stream):
  File "/usr/local/lib/python2.7/dist-packages/docker/utils/json_stream.py", line 22, in stream_as_text
    for data in stream:
  File "/usr/local/lib/python2.7/dist-packages/docker/api/client.py", line 311, in _stream_helper
    yield self._result(response, json=decode)
  File "/usr/local/lib/python2.7/dist-packages/docker/api/client.py", line 226, in _result
    self._raise_for_status(response)
  File "/usr/local/lib/python2.7/dist-packages/docker/api/client.py", line 222, in _raise_for_status
    raise create_api_error_from_http_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/docker/errors.py", line 31, in create_api_error_from_http_exception
    raise cls(e, response=response, explanation=explanation)
APIError: 500 Server Error: Internal Server Error ("Syntax error - can't find = in "ac_environment.http_proxy". Must be of the form: name=value")
EXPECTED RESULTS

service.environment variables can be jinja expressions and are rendered correctly but there is an inconsistency with settings.conductor.environment variables - these do not undergo jinja rendering to be populated.

In order for these to be defined outside the container.yml, variables under settings.conductor.environment variables should ideally be processed in exactly the same way that services.environment variables are.

ACTUAL RESULTS
$ ansible-container --debug --vars-files env.yml build
2017-08-22T13:11:44.811613 Building Docker Engine context... [container.docker.engine] caller_file=/usr/local/lib/python2.7/dist-packages/container/docker/engine.py caller_func=build_conductor_image caller_line=830
2017-08-22T13:11:44.858985 Rendered Jinja Template:       [container.utils] body=FROM debian:latest
ENV ANSIBLE_CONTAINER=1

ENV http_proxy={{         ac_environment.http_proxy }}

ENV https_proxy={{        ac_environment.https_proxy }}

ENV ftp_proxy={{          ac_environment.http_proxy }}

ENV no_proxy={{           ac_environment.no_proxy }}
...

Quoting the varialbe doesn't throw an exception but they are not evaluated as jinja expressions.

$ less container.yml
...
settings:
  conductor:
    environment:
      - http_proxy='{{         ac_environment.http_proxy }}'  #'
      - https_proxy='{{        ac_environment.https_proxy }}' #'
      - ftp_proxy='{{          ac_environment.http_proxy }}'  #'
      - no_proxy='{{           ac_environment.no_proxy }}'    #'
...
$ ansible-container --debug --vars-files env.yml build
2017-08-22T13:15:24.840581 Starting Docker build of Ansible Container Conductor image (please be patient)... [container.docker.engine] caller_file=/usr/local/lib/python2.7/dist-packages/container/docker/engine.py caller_func=build_conductor_image caller_line=895
Step 1/15 : FROM debian:latest
 ---> a20fd0d59cf1
Step 2/15 : ENV ANSIBLE_CONTAINER 1
 ---> Using cache
 ---> 5b42002d64ad
Step 3/15 : ENV http_proxy '{{         ac_environment.http_proxy }}'
 ---> Using cache
 ---> 0c0482aead19
Step 4/15 : ENV https_proxy '{{        ac_environment.https_proxy }}'
 ---> Using cache
 ---> f2006e5efcdb
Step 5/15 : ENV ftp_proxy '{{          ac_environment.http_proxy }}'
 ---> Using cache
 ---> 92ad16cc31bb
Step 6/15 : ENV no_proxy '{{           ac_environment.no_proxy }}'
 ---> Using cache
 ---> b65e54965e08
chouseknecht commented 7 years ago

@shalomb

Not sure if this is a bug or an enhancement, but it seems reasonable to support using template variables within settings.

Thanks for opening this issue!

shalomb commented 7 years ago

@chouseknecht - It's a real inconvenience - without being able to control the https?_proxy envvars for the conductor nothing can be downloaded in environments where you are forced to use a http/https proxy to get out to the net - and ansible-container will just sit there for hours doing nothing. :|

I believe I have a workaround for now by doing this a bit indirectly.

$ less container.yml
...
settings:
  conductor:
    environment: '{{ proxy_env }}'
...

and proxy_env set in a --vars-file like this

proxy_env:
  - http_proxy='http://proxy:3128/'
  - https_proxy='http://proxy:3128/'
  - ftp_proxy='http://proxy:3128/'
  - no_proxy='localhost,127.0.0.1,localaddress,.localdomain.com,169.254.169.254'

Edit: scratch the above - discovered that I had been using a working cached conductor image - looks it is not possible to use jinja at all here.