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

Commit

Permalink
Inital commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ruben Vasconcelos committed Sep 23, 2018
0 parents commit 54f18aa
Show file tree
Hide file tree
Showing 162 changed files with 5,742 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Build files and dirs
build/
*.pyc
__pycache__
*.egg-info
dist

# Docker related files
Dockerfile*

# Testing
htmlcov
.pytest_cache
.coverage

# Other
.git
.gitignore
.gitlab-ci.yml
gitlab-runner/
docs/
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Build files and dirs
build/
__pycache__
*.pyc
*.egg-info
dist

# Testing
htmlcov
.pytest_cache
.coverage

# Other
.DS_Store

# Files with confidential information
pure*.yml
*.pem
*.pub
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM python:3-alpine

LABEL maintainer "[email protected]"

# Update and patch system
RUN apk update \
&& apk add \
git \
docker

# TODO: change this to /path once puller is implemented module/component code
# is moved to their own repos
ENV PYTHONPATH /app:/app/paaspure

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .
20 changes: 20 additions & 0 deletions Dockerfile.binary
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM python:3-alpine

LABEL maintainer "[email protected]"

# Update and patch system
RUN apk update \
&& apk add \
git \
docker

ENV PYTHONPATH /app

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

RUN python setup.py install
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# PaaSPure CLI

> This is was created as part of my computing masters practicum. The PaaSPure CLI was intended to be used for building/deploying PaaS platforms based on user supplied configs. The cli tool will still work without the HUB as users may still pull directly from a git repo.

#### Build

```bash
docker build -t paaspure .
```

#### Run

```bash
docker run -it --rm \
-v "$(pwd)":/app \
-v /var/run/docker.sock:/var/run/docker.sock \
paaspure sh
```

This will mount the current folder as a volume mapped to /app inside the container. So that any changes done on your machine will also be reflected inside the container.

## CI/CD

#### Lint using Flake8
Flak8 is a linting tool, for ensuring compliance with pep8, pyflakes and circular complexity.

```bash
docker run --rm paaspure flake8
```

#### Unit test using PyTest
```bash
docker run --rm paaspure pytest
```

## TODO
* Move pure objects to their own repos.
* Clean up code.
* Remove credentials from config and read from creds file.
3 changes: 3 additions & 0 deletions paaspure/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-

__version__ = "0.0.1"
88 changes: 88 additions & 0 deletions paaspure/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-

import sys
import importlib

from paaspure import settings
from paaspure.argparser import paaSPureParser
from paaspure.generate import PaaSPureGenerator
from paaspure.pull import PaaSPurePuller
from paaspure.utils import read_yaml_file


def main(args=None):
# TODO: This is a bit hacky, fix initial parser.
config_file = 'pure.yml'
if '-f' in sys.argv:
config_file = sys.argv[sys.argv.index('-f') + 1]
elif '--file' in sys.argv:
config_file = sys.argv[sys.argv.index('--file') + 1]

if '-v' in sys.argv or '--verbose' in sys.argv:
settings.DEBUG = '-v' in sys.argv

config = read_yaml_file(
'config',
config_file
)

if 'hub' in config:
settings.HUB = config['hub']

args = __extend_paaspure_parser(config)
__run_command(config, args)


def __extend_paaspure_parser(config):
PaaSPurePuller()
PaaSPureGenerator()

if 'modules' in config and config['modules'] is not None:
for module in config['modules']:
try:
importlib.import_module(module)
except ModuleNotFoundError as err:
args = paaSPureParser.parser.parse_args(sys.argv[1:])

if args.command != 'generate' and args.command != 'pull':
print(err)
print('To import an existing module run:')
print(f'\tpaaspure pull module {module}')
print(f'\tpaaspure pull all')
print('To create a new module run:')
print(f'\tpaaspure generate module {module}')
sys.exit(1)

return paaSPureParser.parser.parse_args(sys.argv[1:])


def __run_command(config, args):
if args.command == 'generate':
PaaSPureGenerator().run(args)
elif args.command == 'pull':
PaaSPurePuller().run(args, config)
elif args.command == 'build' or args.command == 'destroy':
# NOTE: use temp command in case modules modify args. Fine for now but
# there must be a cleaner version (maybe suply modules with deep copy)
command = args.command

if args.command == 'build':
modules = list(config['modules'].keys())
else:
modules = reversed(list(config['modules'].keys()))

for module in modules:
args.command = module
args.subcommand = command
module = importlib.import_module(args.command)
module.instance.execute(config, args)
elif args.command is not None:
module = importlib.import_module(args.command)
module.instance.execute(config, args)
else:
paaSPureParser.parser.print_help()
sys.exit(1)


if __name__ == "__main__":
main()
7 changes: 7 additions & 0 deletions paaspure/abstract/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-

from paaspure.abstract.module import AbstractModule
from paaspure.abstract.component import AbstractComponent
from paaspure.abstract.argparser import AbstractParser

__all__ = ['AbstractModule', 'AbstractComponent', 'AbstractParser']
17 changes: 17 additions & 0 deletions paaspure/abstract/argparser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-

import os
from abc import ABC, abstractmethod


class AbstractParser(ABC):
def __init__(self, filename=__file__):
self.name = os.path.basename(os.path.dirname(filename)),
self.name = ''.join(self.name)
super(AbstractParser, self).__init__()

@abstractmethod
def initialize(self):
"""
This method should implement the module parser.
"""
22 changes: 22 additions & 0 deletions paaspure/abstract/component.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-

from abc import ABC, abstractmethod


class AbstractComponent(ABC):
def __init__(self):
super(AbstractComponent, self).__init__()

@abstractmethod
def build(self):
"""
This method should implement the logic for running a specific
compoenent.
"""

@abstractmethod
def destroy(self):
"""
This method should implement the logic for tearing down the
resources created by run().
"""
75 changes: 75 additions & 0 deletions paaspure/abstract/module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-

import sys
import os
import importlib
from abc import ABC, abstractmethod


class AbstractModule(ABC):
def __init__(self, filename=__file__):
sys.path.append(os.path.dirname(filename))
super(AbstractModule, self).__init__()

@abstractmethod
def execute(self):
"""
This method should implement how to run the module. Think of it
as a layer of abstraction that implements the logic needed to
setup, run and clean up after components.
"""

def general_execute(self, config, args):
if args.subcommand is None:
self.parser.print_help()
sys.exit(1)

components = config['modules'][args.command]['components']
for name, sub_config in components.items():
try:
component = importlib.import_module(f'{name}')
# Use dispatch pattern to invoke method with same name
getattr(component.instance, args.subcommand)(
sub_config,
config['credentials']
)
except ModuleNotFoundError:
self._general_err(args, name)

def general_deploy(self, config, args):
if args.subcommand is None:
self.parser.print_help()
sys.exit(1)

orchestrator = importlib.import_module(
config['modules'][args.command]['orchestrator']
).instance

components = config['modules'][args.command]['components']
component_command = args.subcommand
for name, sub_config in components.items():
try:
component = importlib.import_module(f'{name}').instance

args.subcommand = 'client_connection'
args.command = 'orchestrator'

with orchestrator.execute(config, args) as client:
# Use dispatch pattern to invoke method with same name
getattr(component, component_command)(
sub_config,
client
)
except ModuleNotFoundError:
self._general_err(args, name)

def _general_err(self, args, name):
print(
f"No component named '{name}' in module '{args.command}'"
)
print('To import an existing component run:')
print(f'\tpaaspure pull component {args.command} {name}')
print(f'\tpaaspure pull all')
print('To create a new component run:')
print(f'\tpaaspure generate component {args.command} {name}')
sys.exit(1)
Loading

0 comments on commit 54f18aa

Please sign in to comment.