Skip to content
This repository has been archived by the owner on Mar 23, 2019. It is now read-only.

WIP - buildah support #670

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions container/buildah/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
17 changes: 17 additions & 0 deletions container/buildah/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

from ..config import BaseAnsibleContainerConfig
from ..utils.visibility import getLogger


logger = getLogger(__name__)


class AnsibleContainerConfig(BaseAnsibleContainerConfig):
@property
def image_namespace(self):
return self.project_name

def set_env(self, env):
super(AnsibleContainerConfig, self).set_env(env)
161 changes: 161 additions & 0 deletions container/buildah/engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

import json
import subprocess

try:
import httplib as StatusCodes
except ImportError:
from http import HTTPStatus as StatusCodes

from container import host_only, ENV
from container.docker.engine import Engine as DockerEngine
from container.utils.visibility import getLogger, log_runs

logger = getLogger(__name__)


# got to be named 'Engine'
class Engine(DockerEngine):

# Capabilities of engine implementations
CAP_BUILD_CONDUCTOR = False
CAP_BUILD = True
CAP_DEPLOY = False
CAP_IMPORT = False
CAP_INSTALL = False
CAP_LOGIN = False
CAP_PUSH = False
CAP_RUN = True # required by build
CAP_VERSION = False

display_name = u'buildah'

_client = None

@property
def ansible_build_args(self):
"""Additional commandline arguments necessary for ansible-playbook runs during build"""
return '-c buildah'

@log_runs
@host_only
def run_conductor(self, command, config, base_path, params, engine_name=None, volumes=None):
volumes = volumes or {}
volumes["/var/lib/containers"] = {
"bind": "/var/lib/containers",
"mode": "rw"
}
volumes[base_path] = {'bind': '/src', 'mode': "rw"}

# FIXME: DOCKER_HOST env var
volumes['/var/run/docker.sock'] = {'bind': '/var/run/docker.sock',
'mode': 'rw'}

if not engine_name:
engine_name = __name__.rsplit('.', 2)[-2]
return super(Engine, self).run_conductor(command, config, base_path, params,
engine_name=engine_name,
volumes=volumes)

@log_runs
def container_name_for_service(self, service_name):
return u'%s_%s' % (self.project_name, service_name)

@log_runs
def get_container_id_for_service(self, service_name):
if ENV == "conductor":
j = subprocess.check_output(["buildah", "containers", "--json"])
containers = json.loads(j)
f = self.container_name_for_service(service_name)
matched = [x for x in containers if x["containername"] == f]
if len(matched) == 1:
return matched[0]["id"]
elif len(matched) > 1:
raise Exception()
else:
return None
else: # host
super(Engine, self).get_container_id_for_service(service_name)

@log_runs
def get_image_id_by_tag(self, tag):
if ENV == "conductor":
j = subprocess.check_output(["buildah", "images", "--json"])
images = json.loads(j)
matched = [x for x in images if tag in x["names"]]
if len(matched) == 1:
return matched[0]["id"]
elif len(matched) > 1:
raise Exception()
else:
return None
else: # host
super(Engine, self).get_image_id_by_tag(tag)

@log_runs
def get_image_name_for_image_id(self, image_id):
j = subprocess.check_output(["buildah", "images", "--json"])
images = json.loads(j)
matched = [x for x in images if image_id == x["id"]]
if len(matched) == 1:
return matched[0]["names"][0]
else:
raise Exception()

@log_runs
def run_container(self, image_id, service_name, **kwargs):
if ENV == "conductor":
cont_name = kwargs.get("name", service_name)
image_name = self.get_image_name_for_image_id(image_id)
subprocess.check_call([
"buildah",
"from",
"--name", cont_name,
image_name,
])
config_cmd = ["buildah", "config"]
try:
config_cmd += ["--workingdir", kwargs["working_dir"]]
except KeyError:
pass
for k, v in kwargs["environment"].items():
config_cmd += ["-e", k, v]
subprocess.check_call(config_cmd + [cont_name])
# TODO: volumes during run
else: # host
super(Engine, self).run_container(image_id, service_name, **kwargs)

@log_runs
def image_name_for_service(self, service_name):
if ENV == "conductor":
return u'%s-%s' % (self.project_name.lower(), service_name.lower())
else: # host
super(Engine, self).image_name_for_service(service_name)

@log_runs
def get_latest_image_id_for_service(self, service_name):
if ENV == "conductor":
j = subprocess.check_output(["buildah", "images", "--json"])
images = json.loads(j)
f = self.image_name_for_service(service_name)
matched = [x for x in images if f in x["names"]]
if len(matched) == 1:
return matched[0]["id"]
elif len(matched) > 1:
raise Exception()
else:
return None
else: # host
super(Engine, self).get_latest_image_id_for_service(service_name)

def service_is_running(self, service):
"""
buildah containers are never running; when it exists,
it means it's running and we should either clean or use
"""
if ENV == "conductor":
return self.get_container_id_for_service(service)
else: # host
super(Engine, self).service_is_running(service)
17 changes: 1 addition & 16 deletions container/docker/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import base64
import datetime
import functools
import time
import inspect
import json
Expand All @@ -30,6 +29,7 @@
from container.engine import BaseEngine
from container import utils, exceptions
from container.utils import logmux, text, ordereddict_to_list
from container.utils.visibility import log_runs

try:
import docker
Expand Down Expand Up @@ -69,21 +69,6 @@
REMOVE_HTTP = re.compile('^https?://')


def log_runs(fn):
@functools.wraps(fn)
def __wrapped__(self, *args, **kwargs):
logger.debug(
u'Call: %s.%s' % (type(self).__name__, fn.__name__),
# because log_runs is a decorator, we need to override the caller
# line & function
caller_func='%s.%s' % (type(self).__name__, fn.__name__),
caller_line=inspect.getsourcelines(fn)[-1],
args=args,
kwargs=kwargs,
)
return fn(self, *args, **kwargs)
return __wrapped__

def get_timeout():
timeout = DEFAULT_TIMEOUT_SECONDS
source = None
Expand Down
3 changes: 2 additions & 1 deletion container/docker/templates/conductor-dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ ENV ANSIBLE_CONTAINER=1
{% set distro = conductor_base.split(':')[0] %}
{% if distro in ["fedora"] %}
RUN dnf update -y && \
dnf install -y make gcc git python2 python2-devel curl rsync libffi-devel openssl-devel redhat-rpm-config python2-dnf tar redhat-rpm-config && \
dnf install -y make gcc git python2 python2-devel curl rsync libffi-devel openssl-devel redhat-rpm-config python2-dnf tar redhat-rpm-config \
https://kojipkgs.fedoraproject.org//packages/buildah/0.3/2.gitb9b2a8a.fc26/x86_64/buildah-0.3-2.gitb9b2a8a.fc26.x86_64.rpm && \
dnf clean all
{% elif distro in ["centos"] %}
RUN yum update -y && \
Expand Down
2 changes: 1 addition & 1 deletion container/k8s/base_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from container import conductor_only, host_only
from container import exceptions
from container.docker.engine import Engine as DockerEngine, log_runs
from container.utils.visibility import getLogger
from container.utils.visibility import getLogger, log_runs

logger = getLogger(__name__)

Expand Down
17 changes: 17 additions & 0 deletions container/utils/visibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# the conductor
from __future__ import absolute_import

import functools
import inspect
import logging
import sys
Expand Down Expand Up @@ -111,3 +112,19 @@ def getLogger(name):
],
wrapper_class=BoundLogger,
)


def log_runs(fn):
@functools.wraps(fn)
def __wrapped__(self, *args, **kwargs):
logging.debug(
u'Call: %s.%s' % (type(self).__name__, fn.__name__),
# because log_runs is a decorator, we need to override the caller
# line & function
caller_func='%s.%s' % (type(self).__name__, fn.__name__),
caller_line=inspect.getsourcelines(fn)[-1],
args=args,
kwargs=kwargs,
)
return fn(self, *args, **kwargs)
return __wrapped__