Skip to content
This repository was archived by the owner on Jan 19, 2024. It is now read-only.
Draft
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
6 changes: 3 additions & 3 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ ignored-modules=
# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100
limit-inference-results=160

# List of plugins (as comma separated values of python module names) to load,
# usually to register additional checkers.
Expand Down Expand Up @@ -328,8 +328,8 @@ indent-after-paren=4
indent-string=' '

# Maximum number of characters on a single line.
# 140 was chosen to work nicely on 14" laptops.
max-line-length=140
# 160 was chosen to work nicely on 16" laptops.
max-line-length=160

# Maximum number of lines in a module.
max-module-lines=1000
Expand Down
14 changes: 13 additions & 1 deletion src/dunes/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,19 @@ def load_all_modules_from_dir(plugin_dir):

handle_simple_args()

dunes_sys = dunes(args)
# Set container name. pylint: disable=invalid-name
container_name = None
if args.container_name is not None:
container_name = args.container_name[0]

# Set image name. pylint: disable=invalid-name
image_name = None
if args.image_name is not None:
image_name = args.image_name[0]
if args.start_container is None:
parser.exit_with_help_message("--image-name is only valid with --start-container")

dunes_sys = dunes(container_name, image_name, args)

for module in modules:
if hasattr(module, 'set_dunes'):
Expand Down
18 changes: 16 additions & 2 deletions src/dunes/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ def __init__(self):
description='''DUNES: Docker Utilities for Node Execution and Subsystems.
dunes [ARGUMENTS] -- <COMMANDS> runs any number of commandline commands in the container.
Example: dunes -- cleos --help''')
self._parser.add_argument('-C', '--container-name', nargs=1, metavar="<CONTAINER_NAME>",
help="Use only the container named CONTAINER_NAME for operations.")
self._parser.add_argument('-s', '--start', nargs=1, metavar="<NODE>",
help='start a new node with a given name.')
self._parser.add_argument('-c', '--config', nargs=1, metavar="<CONFIG_DIR>",
Expand Down Expand Up @@ -119,6 +121,8 @@ def __init__(self):
help='Stop the current Docker container.')
self._parser.add_argument('--start-container', action='store_true',
help='Start the current Docker container.')
self._parser.add_argument('--image-name', nargs=1, metavar="<IMAGE_NAME>",
help="Use IMAGE_NAME when starting the container. Only valid for --start-container.")
self._parser.add_argument('--set-core-contract', metavar="<ACCOUNT>",
help='Set the core contract to the specified account '
'(use `eosio` as account for normal system setup).')
Expand Down Expand Up @@ -225,11 +229,21 @@ def add_antler_arguments(self):

@staticmethod
def is_forwarding():
return len(sys.argv) > 1 and sys.argv[1] == '--'
try:
index = sys.argv.index('--')
return index == 1 or (index in [2,3] and (sys.argv[1][:2] == '-C' or sys.argv[1][:16] == '--container-name'))
except ValueError:
return False


@staticmethod
def get_forwarded_args():
return sys.argv[2:]
try:
index = sys.argv.index('--')
return sys.argv[index+1:]
except ValueError:
return None


def parse(self):
try:
Expand Down
121 changes: 84 additions & 37 deletions src/dunes/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,93 @@
class docker_error(Exception):
pass

IMAGES_BASE_URL = 'ghcr.io/antelopeio/'
CONTAINER_NAME = 'dunes_container'
IMAGE_NAME = 'dunes:latest'

class docker:

_container = ""
_image = ""
_container = CONTAINER_NAME
_image = None
_cl_args = None
_dunes_url = 'ghcr.io/antelopeio/dunes:latest'
_dunes_url = ""

def __init__(self, container, image, cl_args):
self._container = container
self._image = image
# pylint: disable=too-many-branches
self._cl_args = cl_args
if container is not None:
self._container = container


# Get list of all containers, search for this container in the list and set some values.
container_found = False
stdout,_,_ = self.execute_docker_cmd(['container', 'ls', '-a'])
for line in stdout.split('\n'):
if self._container in line:
container_found = True
entries = line.split()
if len(entries) > 1:
self._image = entries[1]

# Test to see if the container is running.
container_running = False
if container_found:
# Get the list of running containers.
stdout,_,_ = self.execute_docker_cmd(['container', 'ls'])
container_running = self._container in stdout

# Sanity check users image input.
if image is not None:
if self._image is None:
self._image = image
elif self._image != image:
raise docker_error
self._image = image

# Set image name in the case user didn't set it and there's no container.
if self._image is None:
self._image = IMAGE_NAME

# Set url.
self._dunes_url = IMAGES_BASE_URL+self._image

# No need to continue if the container is already running!
if container_running:
return

# check if container is running
stdout, stderr, exit_code = self.execute_docker_cmd(['container', 'ls'])

# if container is not in the list then create one
if self._container not in stdout:
# check if container is stopped
stdout, stderr, exit_code = self.execute_docker_cmd(
['container', 'ls', '-a'])
# If we found the container, try to start it.
if container_found:
self.execute_docker_cmd(['container', 'start', self._container])
# Get the list of running containers and see what our status is:
stdout,stderr,_ = self.execute_docker_cmd(['container', 'ls'])
if self._container in stdout:
self.execute_docker_cmd(
['container', 'start', self._container])
else:
# download DUNES image
dunes_image = subprocess.check_output(['docker', 'images', '-q', self._image],
stderr=None, encoding='utf-8')

if dunes_image == '':
print('Downloading DUNES image')
self.upgrade()
with subprocess.Popen(['docker', 'tag', self._dunes_url, 'dunes:latest']) as proc:
proc.communicate()

# start a new container
print("Creating docker container [" + self._container + "]")
host_dir = '/'
if platform.system() == 'Windows':
host_dir = 'C:/'

self.execute_docker_cmd(
['run', '-p', '127.0.0.1:8888:8888/tcp', '-p', '127.0.0.1:9876:9876/tcp', '-p',
'127.0.0.1:8080:8080/tcp', '-p', '127.0.0.1:3000:3000/tcp', '-p',
'127.0.0.1:8000:8000/tcp', '-v', host_dir + ':/host', '-d', '--name=' + self._container,
self._image, 'tail', '-f', '/dev/null'])
return
raise docker_error(f"Failed to start {self._container}.\n{stderr}")

# No container was found, so we need to start one.
# Test to see if desired image is available locally.
dunes_image = subprocess.check_output(['docker', 'images', '-q', self._image], stderr=None, encoding='utf-8')
# Nope, try to download it.
if dunes_image == '':
print('Downloading DUNES image')
self.upgrade()

# Create the new container.
print("Creating docker container [" + self._container + "]")
host_dir = '/'
if platform.system() == 'Windows':
host_dir = 'C:/'
self.execute_docker_cmd(['run',
'-p', '127.0.0.1:8888:8888/tcp',
'-p', '127.0.0.1:9876:9876/tcp',
'-p', '127.0.0.1:8080:8080/tcp',
'-p', '127.0.0.1:3000:3000/tcp',
'-p', '127.0.0.1:8000:8000/tcp',
'-v', host_dir + ':/host',
'-d', '--name=' + self._container,
self._image,
'tail', '-f', '/dev/null'])


@staticmethod
def abs_host_path(directory):
Expand Down Expand Up @@ -220,5 +262,10 @@ def execute_bg_cmd(self, cmd):
return self.execute_cmd(cmd + ['&'])

def upgrade(self):
# Pull the new image and give it a local tag.
print(f"['docker', 'pull', {self._dunes_url}]")
with subprocess.Popen(['docker', 'pull', self._dunes_url]) as proc:
proc.communicate()
if self._dunes_url != self._image:
with subprocess.Popen(['docker', 'tag', self._dunes_url, self._image]) as proc:
proc.communicate()
4 changes: 2 additions & 2 deletions src/dunes/dunes.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ class dunes:
_token_priv_key = "5JPJoZXizFVi19wHkboX5fwwEU2jZVvtSJpQkQu3uqgNu8LNdQN"
_token_pub_key = "EOS6v86d8DAxjfGu92CLrnEzq7pySpVWYV2LjaxPaDJJvyf9Vpx5R"

def __init__(self, cl_args):
def __init__(self, container_name=None, image_name=None, cl_args=None):
self._cl_args = cl_args
self._docker = docker('dunes_container', 'dunes:latest', cl_args)
self._docker = docker(container_name, image_name, cl_args)
self._wallet_pw = self.get_wallet_pw()
self._context = context(self._docker)

Expand Down
2 changes: 1 addition & 1 deletion tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# WARNING

These tests are destructive. Do NOT run them when there is important data in your container!
Some of these tests are destructive. Avoid running them when there is important data in your container!

## Getting Started

Expand Down
13 changes: 10 additions & 3 deletions tests/a100_generate_container_image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@
import subprocess
import pytest

from common import TEST_PATH, DUNES_EXE, DUNES_ROOT
from common import TEST_PATH, DUNES_EXE, DUNES_ROOT, stop_dunes_containers


@pytest.mark.safe
def test_init():
stop_dunes_containers()



def get_short_hash():
Expand Down Expand Up @@ -57,9 +63,9 @@ def remove_images(repo_name):

# Remove {repo_name}:* images.
images = subprocess.check_output(['docker', 'images', '-q', repo_name], stderr=None, encoding='utf-8').strip().split('\n')
images = list(set(images)) # Remove duplicates.
for myimg in images:
# pylint: disable=subprocess-run-check
subprocess.run(['docker', 'image', 'rm', myimg, '--force'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, check=False)
subprocess.run(['docker', 'image', 'rm', myimg, '--force'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, check=True)


def remove_tagged_image(tag):
Expand All @@ -81,6 +87,7 @@ def clean_destructive():
# Remove an existing container, then images.
# Send output to subprocess.DEVNULL since we EXPECT docker might tell us containers and images don't exist.
# pylint: disable=subprocess-run-check, line-too-long
subprocess.run(['docker', 'container', 'stop', 'dunes_container'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, check=False)
subprocess.run(['docker', 'container', 'rm', 'dunes_container', '--force'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, check=False)
# Remove dunes:* images.
remove_images('dunes')
Expand Down
32 changes: 32 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import platform
import subprocess

# Find path for tests, root, and executable:
TEST_PATH = os.path.dirname(os.path.abspath(__file__))
Expand All @@ -16,3 +17,34 @@
DEFAULT_HTTP_ADDR = "0.0.0.0:8888"
DEFAULT_P2P_ADDR = "0.0.0.0:9876"
DEFAULT_SHIP_ADDR = "0.0.0.0:8080"


# Constants for test container and images
TEST_CONTAINER_NAME = 'dunes_regression_test_container'
TEST_IMAGE_NAME = 'dunes:latest'



def stop_dunes_containers():
"""Stop any container with 'dune' in the name."""

# Get the list of RUNNING containers.
completed_process = subprocess.run(['docker','container','ls'], check=False, stdout=subprocess.PIPE)

# Parse the list for container names.
for line in completed_process.stdout.decode().split('\n'):
# On a given line, NAME is the final column.
strings = line.split()
index = len(strings)-1
if index < 1:
continue
name = strings[index]

# Test for 'dune' (backwards compatible name) in name.
if 'dune' in name:
subprocess.run(['docker', 'container', 'stop', name], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, check=False)


def destroy_test_container():
"""Destroy any existing test containers."""
subprocess.run(['docker', 'container', 'rm', TEST_CONTAINER_NAME, '--force'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, check=False)
2 changes: 1 addition & 1 deletion tests/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class container:
_container_name = ""
_image_name = ""

def __init__(self, container_name='dunes_container', image_name='dunes:latest'):
def __init__(self, container_name, image_name):
self._container_name = container_name
self._image_name = image_name
self._debug = True
Expand Down
7 changes: 6 additions & 1 deletion tests/test_antler_proj.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import subprocess
import pytest

from common import DUNES_EXE, TEST_PATH
from common import DUNES_EXE, TEST_PATH, stop_dunes_containers


TEST_PROJECT_DIR = os.path.join(TEST_PATH, "antler_test_dir")
Expand All @@ -37,6 +37,11 @@ def remove_existing():
shutil.rmtree(TEST_PROJECT_DIR)


@pytest.mark.safe
def test_init():
stop_dunes_containers()


@pytest.mark.skip(reason="Skipped until the release of antler-proj. "
"See details in https://github.com/AntelopeIO/DUNES/issues/134")
@pytest.mark.safe
Expand Down
Loading