Skip to content

Commit

Permalink
Merge pull request #34 from digitronik/podman
Browse files Browse the repository at this point in the history
Podman support
  • Loading branch information
digitronik authored May 7, 2020
2 parents 45615b7 + e0a8204 commit 600c9cb
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 120 deletions.
40 changes: 10 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h1 align="center"> miqsel</h2>
<h1 align="center"> miqsel</h1>
<h3 align="center">Miq Selenium Server</h3>

<p align="center">
Expand All @@ -16,46 +16,26 @@ src="https://pepy.tech/badge/miqsel"></a>
src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>

Simple command line application to spin [selenium docker container](https://hub.docker.com/r/cfmeqe/cfme_sel_stable) and provide `vnc` access.
Simple command line application to spin [selenium container](http://quay.io/redhatqe/selenium-standalone) and provide `vnc` access.


## Prerequisite:
1. **Docker**:
### Prerequisite:
1. **Podman/Docker**:

For setting `docker` environment follow below steps:
Make sure `podman` or `docker` running on your system.
- [Podman Installation](https://podman.io/getting-started/installation.html)
- [Docker Installation](https://docs.docker.com/engine/install/)

- [Fedora](https://developer.fedoraproject.org/tools/docker/docker-installation.html)
2. **VNC Viewer**:

* Set Repository:
```
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
```
* Install below packages:
```
sudo dnf -y install docker-ce
sudo systemctl start docker
sudo systemctl enable docker
```
* Run docker with non-root User:
```
sudo groupadd docker
sudo usermod -aG docker <non-root-user>
```
- [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) and [others](https://docs.docker.com/install/)
2. **TigerVNC Viewer**:
You can choose any vnc viewer but most of user used _tigervnc_.
- Fedora:
```
sudo dnf install tigervnc
```
- [TigerVNC link for other Distro's](http://tigervnc.bphinz.com/nightly/)
## Installation:
### Installation:
```bash
pip install miqsel --user
```
Expand Down
11 changes: 7 additions & 4 deletions miqsel/conf.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
container:
image: cfmeqe/cfme_sel_stable:latest
client: auto
data_dir: None
image: quay.io/redhatqe/selenium-standalone
name: selenium_container
project: null
network: None
project: None
server_port: 4444
viewer: auto
vnc_port: 5999
data_dir: None
miq:
appliances:
- hostname: null
- hostname: null
browser:
webdriver: Remote
webdriver_options:
Expand Down
15 changes: 13 additions & 2 deletions miqsel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def write(self, cfg):
with open(self.conf_file, "w") as ymlfile:
return safe_dump(cfg, ymlfile, default_flow_style=False)

@property
def container(self):
cfg = self.read()
return cfg["container"]


@click.command(help="Configure Miq Selenium Server")
def config():
Expand All @@ -32,18 +37,24 @@ def config():
cfg["container"]["project"] = click.prompt(
"Miq project working directory", default=cfg["container"]["project"]
)
cfg["container"]["client"] = click.prompt(
"Container Engine [podman/docker]", default=cfg["container"]["client"]
)
cfg["container"]["name"] = click.prompt("Container name", default=cfg["container"]["name"])
cfg["container"]["image"] = click.prompt(
"Docker selenium driver image", default=cfg["container"]["image"]
"Selenium container image", default=cfg["container"]["image"]
)
cfg["container"]["vnc_port"] = click.prompt(
"VNC running on port?", default=cfg["container"]["vnc_port"]
)
cfg["container"]["server_port"] = click.prompt(
"Selenium server running on port?", default=cfg["container"]["server_port"]
)
cfg["container"]["network"] = click.prompt(
"Container network", default=cfg["container"]["network"]
)
cfg["container"]["data_dir"] = click.prompt(
"Testing data mount to directory '/var/tmp'", default=cfg["container"]["data_dir"]
"Testing data mount to directory '/data'", default=cfg["container"]["data_dir"]
)
conf.write(cfg=cfg)
click.echo("Configuration saved successfully...")
2 changes: 1 addition & 1 deletion miqsel/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def env_file(self):
if os.path.isdir("conf"):
# First check miqsel running from project dir
return os.path.join("conf", "env.local.yaml")
elif self.project:
elif self.project != "None":
# Second check miqsel project path set or not
return os.path.join(self.project, "conf", "env.local.yaml")
else:
Expand Down
154 changes: 75 additions & 79 deletions miqsel/server.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,48 @@
import shutil
import subprocess
import time
from subprocess import PIPE
from subprocess import Popen

import click
import docker

from miqsel.config import Configuration
from miqsel.env import LocalEnv

CLIENTS = ["podman", "docker"]
VNC_VIEWERS = ["vncviewer", "vinagre", "xdg-open"]

class Server(object):

class SeleniumContainer(object):
"""Selenium Server Management"""

def __init__(self):
self.client = docker.from_env(version="auto")
self.cfg = Configuration().read()
def __init__(
self, image=None, name=None, server_port=None, vnc_port=None, data_dir=None, network=None
):
self.cfg = Configuration().container
self.image = image or self.cfg["image"]
self.name = name or self.cfg["name"]
self.server_port = server_port or self.cfg["server_port"]
self.vnc_port = vnc_port or self.cfg["vnc_port"]
self.data_dir = data_dir or self.cfg["data_dir"]
self.network = network or self.cfg["network"]

@property
def container(self):
"""
Get running selenium container
:return: if container running return container object else None
"""

try:
return self.client.containers.get(self.cfg["container"]["name"])
except docker.errors.NotFound:
return None
def client(self):
_client = self.cfg["client"]

if _client == "auto":
try:
_client = next(c for c in CLIENTS if shutil.which(c))
except StopIteration:
click.echo(f"No container client found on machine. Install one of {CLIENTS}")
if shutil.which(_client):
return _client
else:
click.echo(f"Container client {_client} not found")

@property
def hostname(self):
"""
Get ip allocated to container
:return: If container running return ip else None
"""

return self.container.attrs["NetworkSettings"]["IPAddress"] if self.container else None
def is_running(self):
cmd = subprocess.run([self.client, "ps"], stdout=subprocess.PIPE)
return self.name in cmd.stdout.decode()

@property
def executor(self):
Expand All @@ -44,11 +51,7 @@ def executor(self):
:return: If container running return executor url else None
"""

return (
f"http://{self.hostname}:{self.cfg['container']['server_port']}/wd/hub"
if self.hostname
else None
)
return f"http://localhost:{self.server_port}/wd/hub"

@property
def vnc(self):
Expand All @@ -57,64 +60,55 @@ def vnc(self):
:return: If container running return vnc url else None
"""

return f"{self.hostname}:{self.cfg['container']['vnc_port']}" if self.hostname else None
return f"localhost:{self.vnc_port}"

def start(self, **kwargs):
"""Start selenium container"""

img = self.cfg["container"]["image"]
name = self.cfg["container"]["name"]
mount_dir = self.cfg["container"]["data_dir"]

if mount_dir != "None":
kwargs.update({"volumes": {mount_dir: {"bind": "/var/tmp", "mode": "ro"}}})

if not self.container:
if not self.client.images.list(name=img):
click.echo("Pulling docker images...")
click.echo("It will take some time; Please wait...")

self.client.containers.run(img, name=name, detach=True, auto_remove=True, **kwargs)

time.sleep(5)

t0 = time.time()
while True:
if self.hostname:
break
elif time.time() > (t0 + 30):
click.echo("Timeout: Fail to get hostname. Check for selenium server status")
exit(0)

elif getattr(self.container, "status", None) == "exited":
self.container.start()
else:
click.echo("Need to check container status...")
if not self.is_running:
cmd = [
self.client,
"run",
"-d",
"--rm",
"--shm-size=2g",
"--expose",
"5999",
"--expose",
"4444",
"-p",
f"{self.vnc_port}:5999",
"-p",
f"{self.server_port}:4444",
"--name",
self.name,
]
if self.network != "None":
cmd.extend(["--network", self.network])
if self.data_dir != "None":
cmd.extend(["-v", f"{self.data_dir}:/data:z"])
cmd.append(self.image)
subprocess.run(cmd)
# hack some time to stable
time.sleep(2)

def stop(self):
"""Stop selenium container if running"""

if getattr(self.container, "status", None) == "running":
self.container.stop()
subprocess.run([self.client, "stop", self.name])

@property
def status(self):
"""
Get status of selenium container
:return: container status if running else stopped
"""

if self.container:
return self.container.status
else:
return "stopped"
return "running" if self.is_running else "stopped"


@click.command(help="Status of Selenium Server")
def status():
"""status command"""

miq = Server()
miq = SeleniumContainer()
click.echo(miq.status)


Expand All @@ -123,8 +117,8 @@ def status():
def start(ctx):
"""start command"""

miq = Server()
if miq.status == "stopped":
miq = SeleniumContainer()
if not miq.is_running:
try:
miq.start()
click.echo("Selenium Server started")
Expand All @@ -143,8 +137,8 @@ def start(ctx):
def stop():
"""stop command"""

miq = Server()
if miq.status == "running":
miq = SeleniumContainer()
if miq.is_running:
miq.stop()
click.echo("Selenium Server stopped")
else:
Expand All @@ -155,7 +149,7 @@ def stop():
def executor():
"""executor url command"""

miq = Server()
miq = SeleniumContainer()
if miq.status == "running":
click.echo(miq.executor)
else:
Expand All @@ -166,7 +160,7 @@ def executor():
def vnc():
"""vnc url command"""

miq = Server()
miq = SeleniumContainer()
if miq.status == "running":
click.echo(miq.vnc)
else:
Expand All @@ -181,11 +175,13 @@ def viewer(url):
:param url: Server url with port <hostname:port>
"""

url = url if url else Server().vnc
url = url if url else SeleniumContainer().vnc
try:
_viewer = next(v for v in VNC_VIEWERS if shutil.which(v))
except StopIteration:
click.echo(f"No vnc viewer found. Install one of {VNC_VIEWERS}")

if url:
try:
Popen(["vncviewer", url], stdout=PIPE)
except FileNotFoundError:
click.echo("Need vnc viewer... Check README")
subprocess.Popen([_viewer, url], stdout=subprocess.PIPE)
else:
click.echo("Server not running...")
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
with open("README.md") as readme_file:
readme = readme_file.read()

install_requirements = ["Click>=5.0", "docker>=3.1", "ruamel.yaml~=0.15"]
install_requirements = ["Click>=5.0", "ruamel.yaml~=0.15"]

setup_requirements = ["setuptools_scm"]

Expand All @@ -20,6 +20,7 @@
"Natural Language :: English",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development :: Quality Assurance",
"Topic :: Software Development :: Testing",
Expand Down
Loading

0 comments on commit 600c9cb

Please sign in to comment.