Skip to content
This repository has been archived by the owner on Jan 13, 2020. It is now read-only.
/ accelpy Public archive

Commit

Permalink
1.0.0-beta.19
Browse files Browse the repository at this point in the history
  • Loading branch information
JGoutin committed Aug 13, 2019
1 parent 48b0f34 commit 894eb4e
Show file tree
Hide file tree
Showing 20 changed files with 408 additions and 203 deletions.
2 changes: 1 addition & 1 deletion accelpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
__version__ = '1.0.0-beta.18'
__version__ = '1.0.0-beta.19'
__copyright__ = "Copyright 2019 Accelize"
__licence__ = "Apache 2.0"

Expand Down
2 changes: 1 addition & 1 deletion accelpy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def _provider_completer(prefix, parsed_args, **_):
# Else get providers from application and cache them
if not providers:
from accelpy._application import Application
providers = Application(application).environments
providers = Application(application).providers
set_cli_cache(cached, list(providers))

# Filter with prefix
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ def do_GET(self):
"""GET"""
process = run(['/opt/xilinx/xrt/bin/awssak', 'list'],
stderr=STDOUT, stdout=PIPE)
self.send_response(500 if process.returncode else 200)
self.send_response(500 if (
process.returncode or b"[0] " not in process.stdout) else 200)
self.end_headers()
self.wfile.write(process.stdout)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
roles:
- role: container_service
vars:
package_name: accelize/accelpy-ci
package_version: container_service
app_packages:
- name: accelize/accelpy-ci
version: container_service
accelize_drm_disabled: false
accelize_drm_cred_dst: /home/appuser/.accelize_drm/cred.json
firewall_rules:
Expand Down
9 changes: 5 additions & 4 deletions accelpy/_ansible/roles/container_service/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@

- name: Pull application container image using Docker
docker_image:
name: "{{ package_name }}"
tag: "{{ package_version | default('latest') }}"
name: "{{ app_packages[0].name }}"
tag: "{{ app_packages[0].version | default('latest') }}"
state: present
source: pull
register: docker_image_info
Expand All @@ -62,8 +62,9 @@

- name: Pull application container image using Podman
podman_image:
name: "{{ package_repository | default('docker.io') }}/{{ package_name }}"
tag: "{{ package_version | default('latest') }}"
name: "{{ app_packages[0].repository | default('docker.io') }}/
{{ app_packages[0].name }}"
tag: "{{ app_packages[0].version | default('latest') }}"
state: present
register: podman_image_info
become_user: appuser
Expand Down
14 changes: 10 additions & 4 deletions accelpy/_ansible/roles/kubernetes_node/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,34 @@
state: present
retries: 10
delay: 1
when: master_node | bool

- name: Ensure kubectl bash completion is enabled for current user
lineinfile:
path: "/home/{{ ansible_user }}/.bashrc"
line: source <(kubectl completion bash)
state: present
when: master_node | bool

- name: Ensure ".kube" directory exists in current user home directory
file:
path: "/home/{{ ansible_user }}/.kube"
state: directory
when: master_node | bool

- name: Ensure current user has read access to the K8s configuration
file:
path: /etc/kubernetes/admin.conf
group: "{{ ansible_user }}"
mode: 0640
when: master_node | bool

- name: Symlink the kubectl "admin.conf" to "~/.kube/conf"
file:
src: /etc/kubernetes/admin.conf
dest: "/home/{{ ansible_user }}/.kube/config"
state: link
when: master_node | bool

- name: Ensure FPGA Kubernetes device plugin is present
get_url:
Expand All @@ -46,9 +51,10 @@
delay: 1

- name: Ensure FPGA Kubernetes device plugin is enabled as deamonset
command: kubectl create -f /etc/kubernetes/fpga-device-plugin.yml
command: kubectl apply -f /etc/kubernetes/fpga-device-plugin.yml
when: master_node | bool

- name: Ensure Kubernetes deployment/pod is deployed
command: "kubectl apply -f {{ package_name }}"
when: master_node | bool
- name: Ensure Kubernetes YAML files are applied
command: "kubectl apply -f {{ item.name }}"
when: master_node | bool and (item.type == "kubernetes_yaml")
with_items: "{{ app_packages }}"
159 changes: 110 additions & 49 deletions accelpy/_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
default={})
},
'package': {
'_node': dict,
'_node': list,
'type': dict(
default='container_image',
values=('container_image', 'vm_image', 'kubernetes_deployment')),
values=('container_image', 'vm_image', 'kubernetes_yaml')),
'name': dict(
required=True,),
'version': dict(),
Expand Down Expand Up @@ -92,7 +92,7 @@ class Application:
"""

def __init__(self, definition):
self._environments = set()
self._providers = set()

# Load from dict
if isinstance(definition, dict):
Expand All @@ -103,10 +103,20 @@ def __init__(self, definition):
self._path = fsdecode(definition)
definition = yaml_read(self._path)

# Validate content
self._definition = self._validate(definition)

# Cache definition for each provider
self._provider_definition = self._create_provider_definitions()

def __getitem__(self, key):
return self._definition.__getitem__(key)
# Get global definition
if key in FORMAT:
return self._definition[key]

# Get provider cached definition, or default definition
return self._provider_definition.get(
key, self._provider_definition[None])

@classmethod
def from_id(cls, application):
Expand Down Expand Up @@ -170,34 +180,67 @@ def push(self):
self._definition, 'post')

@property
def environments(self):
def providers(self):
"""
Environments specified in definition.
Providers specified in definition.
Returns:
set of str: Environments
set of str: Providers
"""
return self._environments
return self._providers

def get(self, section, key, env=None):
def _create_provider_definitions(self):
"""
Create cached definition for each provider + a default unspecified
provider.
Returns:
dict: Definition
"""
Return value from definition.
result = dict()
for provider in list(self._providers) + [None]:
result[provider] = provider_definition = dict()

for section in self._definition:
node = self._definition[section]

if isinstance(node, dict):
provider_definition[section] = self._get_provider_node(
node, provider)
else:
provider_definition[section] = [
self._get_provider_node(node[i], provider)
for i in range(len(node))]

return result

def _get_provider_node(self, node, provider):
"""
Get node for a specific provider.
Args:
section (str): Definition section.
key (str): Definition key.
env (str): Environment. None for use default environment value.
node (dict): Node.
provider (str or None): provider.
Returns:
Value
dict: Node
"""
# Return specific environment value
try:
return self._definition[section][env][key]
result_node = node.copy()

# Return default environment value
# Update node with provider specific values
try:
result_node.update(node[provider])
except KeyError:
return self._definition[section][key]
pass

# Clean up other Providers
for key in self._providers:
try:
del result_node[key]
except KeyError:
pass

return result_node

def save(self, path=None):
"""
Expand Down Expand Up @@ -232,7 +275,7 @@ def _validate(self, definition):
# Create missing definition section
section = definition[section_name] = node_type()

self._validate_section(
definition[section_name] = self._validate_section(
node_type, section, section_name, section_format)

# Check for unknown sections
Expand All @@ -256,18 +299,30 @@ def _validate_section(
Raises:
ValueError: Error in section format.
Returns:
dict or list: section.
"""
if not isinstance(section, node_type):
if node_type == dict:
raise ConfigurationException(
f'The section "{section_name}" must be a "mapping".')
else:
section = [section]

if section_name == 'package' and not section:
raise ConfigurationException(
f'The section "{section_name}" must be a '
f'{"mapping" if node_type == dict else "list"}.')
f'The section "{section_name}" must contain a least one '
f'"mapping".')

for node in (section if isinstance(section, list) else (section,)):
args = (node, section_format, section_name)
self._validate_node(*args)
if not self._validate_env_node(*args):
if not self._validate_provider_node(*args):
self._check_required(*args)

return section

@staticmethod
def _validate_node(node, node_format, section_name):
"""
Expand Down Expand Up @@ -299,7 +354,7 @@ def _validate_node(node, node_format, section_name):
@staticmethod
def _check_required(node, node_format, section_name):
"""
Check for required value in default env.
Check for required value in default provider.
Args:
node (dict): Node to validate
Expand All @@ -314,7 +369,7 @@ def _check_required(node, node_format, section_name):
if key == '_node':
continue

# Check required value for default environment
# Check required value for default provider
if node_format[key].get('required', False) and node[key] is None:
raise ConfigurationException(
f'The "{key}" key in "{section_name}" section is required.')
Expand Down Expand Up @@ -384,9 +439,9 @@ def _check_value(key, key_format, value, section_name):

return value

def _validate_env_node(self, node, node_format, section_name):
def _validate_provider_node(self, node, node_format, section_name):
"""
Validate an environment override node.
Validate an provider override node.
Args:
node (dict): Node to validate
Expand All @@ -397,50 +452,56 @@ def _validate_env_node(self, node, node_format, section_name):
ValueError: Error in node format.
Returns:
bool: True in at least one env found.
bool: True in at least one provider found.
"""
env_found = False
for env in node:
provider_found = False
for provider in node:

# Not an env
if env in node_format:
# Not an provider
if provider in node_format:
continue

# Env found
self._environments.add(env)
env_found = True
env_node = node[env]
if provider in FORMAT:
raise ConfigurationException(
f'Provider in "{section_name}" section cannot be named with'
f' reserved name "{provider}".')

# Provider found
self._providers.add(provider)
provider_found = True
provider_node = node[provider]

# Env that is not a dict is likely an unknown key
if not isinstance(env_node, dict) or env_node == '_node':
# Provider that is not a dict is likely an unknown key
if not isinstance(provider_node, dict) or provider_node == '_node':
raise ConfigurationException(
f'Unknown "{env_node}" key in "{section_name}" section.')
f'Unknown "{provider_node}" key in '
f'"{section_name}" section.')

# Check environment integrity
# Check provider integrity
for key in node_format:

if key == '_node':
continue

value = env_node.get(key, node.get(key))
value = provider_node.get(key, node.get(key))
key_format = node_format[key]

# Required value for environment
# Required value for provider
if key_format.get('required', False) and value is None:
raise ConfigurationException(
f'The "{key}" key in "{section_name}" section is '
f'required for "{env}" environment.')
f'required for "{provider}" provider.')

# Check value
if key in env_node:
env_node[key] = Application._check_value(
if key in provider_node:
provider_node[key] = Application._check_value(
key, key_format, value, section_name)

# Check for unknown keys in environment
for key in env_node:
# Check for unknown keys in provider
for key in provider_node:
if key not in node_format or key == '_node':
raise ConfigurationException(
f'Unknown "{key}" key in "{section_name}" section '
f'for "{env}" environment.')
f'for "{provider}" provider.')

return env_found
return provider_found
Loading

0 comments on commit 894eb4e

Please sign in to comment.