Skip to content

Commit

Permalink
Added common module to import in tern exec
Browse files Browse the repository at this point in the history
- common.py contains common modules that can
be used by subcommands
- tern now runs as an independent executable
- Added some modules to commands.py to support
base image inspection

Signed-off-by: Nisha K <[email protected]>
  • Loading branch information
Nisha K committed Aug 21, 2017
1 parent 1f1a703 commit 484d5b9
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 45 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
__pycache__
*.pyc
sources
sources.txt
report.txt
68 changes: 68 additions & 0 deletions common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'''
Common functions
'''
import sys

from utils import dockerfile as df
from utils import commands as cmds
from utils import cache as c

# constants strings
no_image_tag = '''No base image and/or tag listed in the command library \n
To add one, make an entry in command_lib/base.yml'''
no_command = '''No listing of hardcoded or retrieval steps for {image_tag} \n
To tell the tool this information make an entry in command_lib/base.yml'''
no_invocation = '''No invocation steps to perform within a container nor
on the host machine.\n To tell the tool how to retrieve this information,
make an entry in command_lib/base.yml'''


def check_cache_base(base_image_tag):
'''Given a base image tag return a list of packages for the layers
in the cache
TODO: images and layers are used intergably for the base image
Ideally the packages should be identified by the filesystem and the image
ID'''
image_tag_string = base_image_tag[0] + df.tag_separator + base_image_tag[1]
if not cmds.check_image(image_tag_string):
cmds.docker_command(cmds.pull, True, image_tag_string)
image_id = cmds.get_image_id(image_tag_string)
return c.get_packages(image_id)


def get_base_dict(base_image_tag):
'''Return the base dictionary from the command library'''
image = base_image_tag[0]
# check image
listing = cmds.query_library(['base', image])
if listing:
if base_image_tag[1] == 'latest':
tag = cmds.query_library(['base', image, 'latest'])
else:
tag = base_image_tag[1]
# check tag
listing = cmds.query_library(['base', image, tag])
return listing


def get_base_packages(base_image_tag):
'''Get the list of packages that are installed in the base layer using
the invocations listed in the base command library
If they don't exist inform the user'''
# TODO: all of the commands listed so far are invoked within a container
# there should be some mechanism where the commands get executed one
# by one but also outside and inside the container
image_tag_string = base_image_tag[0] + df.tag_separator + base_image_tag[1]
base_dict = get_base_dict(base_image_tag)
package_list = []
if base_dict:
names_dict = base_dict.get('names')
if names_dict:
package_list = cmds.invoke_in_container(
names_dict['container']['invoke'], image_tag_string,
base_dict['shell'])
else:
print(no_command.format(image_tag=image_tag_string))
else:
print(no_image_tag)
return package_list
27 changes: 8 additions & 19 deletions tern
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,10 @@
Tern executable
'''

import argparse

from utils import dockerfile as df
from utils import commands as cmds
from utils import cache as c
import report


def check_cache_base(base_image_tag):
'''Given a base image tag
1. Check if that image and tag exist, if not then pull the base
image
2. Get the image ID of the base image
3. Check against the cache if the image exists
4. If it doesn't, run the commands prescribed
5. Parse the results and place back in the cache
6. Return a list of packages for that layer'''
import argparse

import report as r

def main(args):
'''Given a Dockerfile do the following:
Expand All @@ -30,15 +16,18 @@ def main(args):
command library
3. If there are any retrieval steps execute those
4. Write a report'''
docker_commands = df.get_directive_list(df.get_command_list(args.dockerfile))
docker_commands = df.get_directive_list(
df.get_command_list(args.dockerfile))
base_image_tag = df.get_base_image_tag(
df.get_base_instructions(docker_commands))

# check the image against the cache

# for now the image that gets build will be tagged with an image name
# and the name of the base image on which it is being built
# The image name is in commands.py
image_tag_string = cmds.image + df.tag_separator + base_image_tag[0]
packages = cmds.get_packages(docker_commands)
# convert to a layer

# for now remove all the packages that possibly got uninstalled
packages['recognized'] = cmds.remove_uninstalled(packages['recognized'])
Expand All @@ -53,7 +42,7 @@ def main(args):
if cmds.check_all_pkgs(command):
# in this case there is probably a url retrieval step
# we can start a container here
cmds.start_container(dockerfile, image_tag_string)
cmds.start_container(args.dockerfile, image_tag_string)
# we can get the url retrieval step here
pkg_rules = cmds.command_lib[command]['packages'][0]
if 'url_retrieval' in pkg_rules.keys():
Expand Down
46 changes: 21 additions & 25 deletions utils/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'''
# docker commands
check_images = ['docker', 'images']
pull = ['docker', 'pull']
build = ['docker', 'build']
run = ['docker', 'run', '-td']
check_running = ['docker', 'ps', '-a']
Expand Down Expand Up @@ -246,39 +247,34 @@ def get_base_shell(image_tuple):
return shell


def invoke_in_container(invoke_dict, package, image_tag_string, shell):
def invoke_in_container(invoke_dict, image_tag_string, shell, package=''):
'''Invoke the commands from the invoke dictionary within a running
container. The invoke dictionary looks like:
<step>:
command: <the command to invoke>
args: <True/False>
update this dict with the result from each command invoked'''
<step>: <command>
update this dict with the result from each command invoked
<step>: <result>'''
count = len(invoke_dict.keys())
result = ''
for step in range(1, count + 1):
full_cmd = ''
command = invoke_dict[step]['command']
# check if there are any arg rules
if 'args' in invoke_dict[step].keys():
if invoke_dict[step]['args']:
full_cmd = command + ' ' + package
else:
full_cmd = command
try:
result = docker_command(execute, True, container,
shell, '-c', full_cmd)
except:
print("Error executing command inside the container")
break
else:
print("Please specify if the package name should be an argument"
" for this command")
break
return result
full_cmd = invoke_dict[step].format(package=package)
try:
invoke_dict[step] = docker_command(execute, True, container,
shell, '-c', full_cmd)
except:
print("Error executing command inside the container")
return invoke_dict


def get_image_id(image_tag_string):
'''Get the image ID by inspecting the image'''
result = docker_command(inspect,
True, "-f'{{json .Id}}'", image_tag_string)
return result.split(':').pop()


def query_library(keys):
'''Given a list of keys recover the value in the library
If the key doesn't exist return nothing'''
value = command_lib.get(keys.pop(0))
while value and keys:
value = value.get(keys.pop(0))
return value

0 comments on commit 484d5b9

Please sign in to comment.