shellfoundry 1.2.25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shellfoundry/__init__.py +8 -0
- shellfoundry/__main__.py +7 -0
- shellfoundry/bootstrap.py +169 -0
- shellfoundry/commands/__init__.py +0 -0
- shellfoundry/commands/config_command.py +87 -0
- shellfoundry/commands/delete_command.py +24 -0
- shellfoundry/commands/dist_command.py +34 -0
- shellfoundry/commands/extend_command.py +182 -0
- shellfoundry/commands/generate_command.py +44 -0
- shellfoundry/commands/get_templates_command.py +151 -0
- shellfoundry/commands/install_command.py +81 -0
- shellfoundry/commands/list_command.py +110 -0
- shellfoundry/commands/new_command.py +393 -0
- shellfoundry/commands/pack_command.py +45 -0
- shellfoundry/commands/show_command.py +55 -0
- shellfoundry/data/standards.json +44 -0
- shellfoundry/data/templates.yml +117 -0
- shellfoundry/decorators/__init__.py +1 -0
- shellfoundry/decorators/standards.py +20 -0
- shellfoundry/decorators/version_check.py +52 -0
- shellfoundry/exceptions.py +52 -0
- shellfoundry/models/__init__.py +0 -0
- shellfoundry/models/install_config.py +82 -0
- shellfoundry/models/shell_template.py +22 -0
- shellfoundry/models/shellfoundry_settings.py +13 -0
- shellfoundry/utilities/__init__.py +114 -0
- shellfoundry/utilities/archive_creator.py +35 -0
- shellfoundry/utilities/cloudshell_api/__init__.py +1 -0
- shellfoundry/utilities/cloudshell_api/client_wrapper.py +71 -0
- shellfoundry/utilities/config/__init__.py +0 -0
- shellfoundry/utilities/config/config_context.py +44 -0
- shellfoundry/utilities/config/config_file_creation.py +32 -0
- shellfoundry/utilities/config/config_providers.py +50 -0
- shellfoundry/utilities/config/config_record.py +24 -0
- shellfoundry/utilities/config_reader.py +154 -0
- shellfoundry/utilities/constants.py +37 -0
- shellfoundry/utilities/cookiecutter_integration.py +67 -0
- shellfoundry/utilities/driver_generator.py +121 -0
- shellfoundry/utilities/filters.py +45 -0
- shellfoundry/utilities/installer.py +44 -0
- shellfoundry/utilities/modifiers/__init__.py +0 -0
- shellfoundry/utilities/modifiers/configuration/__init__.py +0 -0
- shellfoundry/utilities/modifiers/configuration/aggregated_modifiers.py +26 -0
- shellfoundry/utilities/modifiers/configuration/password_modification.py +48 -0
- shellfoundry/utilities/modifiers/definition/__init__.py +0 -0
- shellfoundry/utilities/modifiers/definition/definition_modification.py +205 -0
- shellfoundry/utilities/package_builder.py +152 -0
- shellfoundry/utilities/python_dependencies_packager.py +53 -0
- shellfoundry/utilities/repository_downloader.py +76 -0
- shellfoundry/utilities/shell_config_reader.py +59 -0
- shellfoundry/utilities/shell_datamodel_merger.py +44 -0
- shellfoundry/utilities/shell_package.py +59 -0
- shellfoundry/utilities/shell_package_builder.py +149 -0
- shellfoundry/utilities/shell_package_installer.py +231 -0
- shellfoundry/utilities/standards/__init__.py +3 -0
- shellfoundry/utilities/standards/consts.py +2 -0
- shellfoundry/utilities/standards/standards_retriever.py +32 -0
- shellfoundry/utilities/standards/standards_versions.py +34 -0
- shellfoundry/utilities/temp_dir_context.py +17 -0
- shellfoundry/utilities/template_retriever.py +309 -0
- shellfoundry/utilities/template_url.py +38 -0
- shellfoundry/utilities/template_versions.py +47 -0
- shellfoundry/utilities/validations/__init__.py +2 -0
- shellfoundry/utilities/validations/shell_generation_validation.py +29 -0
- shellfoundry/utilities/validations/shell_name_validations.py +10 -0
- shellfoundry/utilities/version_utilities.py +19 -0
- shellfoundry-1.2.25.dist-info/LICENSE +201 -0
- shellfoundry-1.2.25.dist-info/METADATA +417 -0
- shellfoundry-1.2.25.dist-info/RECORD +72 -0
- shellfoundry-1.2.25.dist-info/WHEEL +5 -0
- shellfoundry-1.2.25.dist-info/entry_points.txt +2 -0
- shellfoundry-1.2.25.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from io import open
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
from shellfoundry.models.install_config import (
|
|
10
|
+
DEFAULT_AUTHOR,
|
|
11
|
+
DEFAULT_DOMAIN,
|
|
12
|
+
DEFAULT_GITHUB_LOGIN,
|
|
13
|
+
DEFAULT_GITHUB_PASSWORD,
|
|
14
|
+
DEFAULT_HOST,
|
|
15
|
+
DEFAULT_ONLINE_MODE,
|
|
16
|
+
DEFAULT_PASSWORD,
|
|
17
|
+
DEFAULT_PORT,
|
|
18
|
+
DEFAULT_TEMPLATE_LOCATION,
|
|
19
|
+
DEFAULT_USERNAME,
|
|
20
|
+
InstallConfig,
|
|
21
|
+
)
|
|
22
|
+
from shellfoundry.models.shellfoundry_settings import (
|
|
23
|
+
DEFAULT_DEFAULT_VIEW,
|
|
24
|
+
ShellFoundrySettings,
|
|
25
|
+
)
|
|
26
|
+
from shellfoundry.utilities.config.config_providers import DefaultConfigProvider
|
|
27
|
+
|
|
28
|
+
INSTALL = "install"
|
|
29
|
+
|
|
30
|
+
HOST = "host"
|
|
31
|
+
PORT = "port"
|
|
32
|
+
USERNAME = "username"
|
|
33
|
+
PASSWORD = "password"
|
|
34
|
+
DOMAIN = "domain"
|
|
35
|
+
AUTHOR = "author"
|
|
36
|
+
ONLINE_MODE = "online_mode"
|
|
37
|
+
TEMPLATE_LOCATION = "template_location"
|
|
38
|
+
GITHUB_LOGIN = "github_login"
|
|
39
|
+
GITHUB_PASSWORD = "github_password"
|
|
40
|
+
|
|
41
|
+
DEFAULT_VIEW = "defaultview"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_with_default(install_config, parameter_name, default_value):
|
|
45
|
+
"""Get configuration with default values.
|
|
46
|
+
|
|
47
|
+
:param install_config: A dict represents the install section inside the configuration file # noqa: E501
|
|
48
|
+
:param parameter_name: Specific key inside the install section
|
|
49
|
+
:param default_value: Default value in cases that the key cannot be found
|
|
50
|
+
:return: The value of the key in the configuration file or default value if key cannot be found # noqa: E501
|
|
51
|
+
"""
|
|
52
|
+
return (
|
|
53
|
+
install_config[parameter_name]
|
|
54
|
+
if install_config and parameter_name in install_config
|
|
55
|
+
else default_value
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Configuration(object):
|
|
60
|
+
def __init__(self, reader, config_provider=None):
|
|
61
|
+
self.reader = reader
|
|
62
|
+
self.config_provider = config_provider or DefaultConfigProvider()
|
|
63
|
+
|
|
64
|
+
def read(self):
|
|
65
|
+
config_path = self.config_provider.get_config_path()
|
|
66
|
+
|
|
67
|
+
if config_path is None or not os.path.isfile(config_path):
|
|
68
|
+
return self.reader.get_defaults()
|
|
69
|
+
|
|
70
|
+
with open(config_path) as stream:
|
|
71
|
+
config = yaml.safe_load(stream.read())
|
|
72
|
+
|
|
73
|
+
if not config or INSTALL not in config:
|
|
74
|
+
return self.reader.get_defaults()
|
|
75
|
+
|
|
76
|
+
return self.reader.read_from_config(config[INSTALL])
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def readall(config_path, mark_defaults=None):
|
|
80
|
+
"""Reads configuration from given file.
|
|
81
|
+
|
|
82
|
+
Missing keys will be filled with their defaults.
|
|
83
|
+
"""
|
|
84
|
+
config_data = None
|
|
85
|
+
if os.path.exists(config_path):
|
|
86
|
+
with open(config_path, mode="r", encoding="utf8") as conf_file:
|
|
87
|
+
config_data = yaml.safe_load(conf_file)
|
|
88
|
+
|
|
89
|
+
if not config_data or INSTALL not in config_data:
|
|
90
|
+
config_data = {INSTALL: {}}
|
|
91
|
+
|
|
92
|
+
mark_defaults_f = Configuration._mark_defaults
|
|
93
|
+
install_cfg_def = {
|
|
94
|
+
(k, mark_defaults_f(v, mark_defaults))
|
|
95
|
+
for k, v in InstallConfig.get_default().__dict__.items()
|
|
96
|
+
}
|
|
97
|
+
sf_cfg_def = {
|
|
98
|
+
(k, mark_defaults_f(v, mark_defaults))
|
|
99
|
+
for k, v in ShellFoundrySettings.get_default().__dict__.items()
|
|
100
|
+
}
|
|
101
|
+
all_cfg = dict(install_cfg_def)
|
|
102
|
+
all_cfg.update(sf_cfg_def)
|
|
103
|
+
all_cfg.update(config_data[INSTALL])
|
|
104
|
+
return {INSTALL: all_cfg}
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def _mark_defaults(value, mark_defaults_char):
|
|
108
|
+
if not mark_defaults_char:
|
|
109
|
+
return str(value)
|
|
110
|
+
return "{value} {default_char}".format(
|
|
111
|
+
value=str(value), default_char=mark_defaults_char
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class CloudShellConfigReader(object):
|
|
116
|
+
def get_defaults(self):
|
|
117
|
+
return InstallConfig.get_default()
|
|
118
|
+
|
|
119
|
+
def read_from_config(self, config):
|
|
120
|
+
host = get_with_default(config, HOST, DEFAULT_HOST)
|
|
121
|
+
port = get_with_default(config, PORT, DEFAULT_PORT)
|
|
122
|
+
username = get_with_default(config, USERNAME, DEFAULT_USERNAME)
|
|
123
|
+
password = get_with_default(config, PASSWORD, DEFAULT_PASSWORD)
|
|
124
|
+
domain = get_with_default(config, DOMAIN, DEFAULT_DOMAIN)
|
|
125
|
+
author = get_with_default(config, AUTHOR, DEFAULT_AUTHOR)
|
|
126
|
+
online_mode = get_with_default(config, ONLINE_MODE, DEFAULT_ONLINE_MODE)
|
|
127
|
+
template_location = get_with_default(
|
|
128
|
+
config, TEMPLATE_LOCATION, DEFAULT_TEMPLATE_LOCATION
|
|
129
|
+
)
|
|
130
|
+
github_login = get_with_default(config, GITHUB_LOGIN, DEFAULT_GITHUB_LOGIN)
|
|
131
|
+
github_password = get_with_default(
|
|
132
|
+
config, GITHUB_PASSWORD, DEFAULT_GITHUB_PASSWORD
|
|
133
|
+
)
|
|
134
|
+
return InstallConfig(
|
|
135
|
+
host,
|
|
136
|
+
port,
|
|
137
|
+
username,
|
|
138
|
+
password,
|
|
139
|
+
domain,
|
|
140
|
+
author,
|
|
141
|
+
online_mode,
|
|
142
|
+
template_location,
|
|
143
|
+
github_login,
|
|
144
|
+
github_password,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class ShellFoundryConfig(object):
|
|
149
|
+
def get_defaults(self):
|
|
150
|
+
return ShellFoundrySettings.get_default()
|
|
151
|
+
|
|
152
|
+
def read_from_config(self, config):
|
|
153
|
+
defaultview = get_with_default(config, DEFAULT_VIEW, DEFAULT_DEFAULT_VIEW)
|
|
154
|
+
return ShellFoundrySettings(defaultview)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"TOSCA_META_LOCATION",
|
|
8
|
+
"TEMPLATE_AUTHOR_FIELD",
|
|
9
|
+
"TEMPLATE_VERSION",
|
|
10
|
+
"TEMPLATE_BASED_ON",
|
|
11
|
+
"CLOUDSHELL_MAX_RETRIES",
|
|
12
|
+
"CLOUDSHELL_RETRY_INTERVAL_SEC",
|
|
13
|
+
"DEFAULT_TIME_WAIT",
|
|
14
|
+
"TEMPLATE_PROPERTY",
|
|
15
|
+
"TEMPLATES_YML",
|
|
16
|
+
"SERVER_VERSION_KEY",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
CLOUDSHELL_MAX_RETRIES = 5
|
|
20
|
+
CLOUDSHELL_RETRY_INTERVAL_SEC = 0.5
|
|
21
|
+
DEFAULT_TIME_WAIT = 1.0
|
|
22
|
+
METADATA_AUTHOR_FIELD = "Created-By"
|
|
23
|
+
TEMPLATE_AUTHOR_FIELD = "metadata/template_author"
|
|
24
|
+
TEMPLATE_VERSION = "metadata/template_version"
|
|
25
|
+
TEMPLATE_BASED_ON = "metadata/template_based_on"
|
|
26
|
+
TEMPLATE_INFO_FILE = "cookiecutter.json"
|
|
27
|
+
TEMPLATE_PROPERTY = {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"default": "fast",
|
|
30
|
+
"description": "Some attribute description",
|
|
31
|
+
"constraints": [{"valid_values": ["fast", "slow"]}],
|
|
32
|
+
}
|
|
33
|
+
TEMPLATES_YML = (
|
|
34
|
+
"https://raw.github.com/QualiSystems/shellfoundry/master/templates_v1.yml"
|
|
35
|
+
)
|
|
36
|
+
TOSCA_META_LOCATION = os.path.join("TOSCA-Metadata", "TOSCA.meta")
|
|
37
|
+
SERVER_VERSION_KEY = "server_version"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import datetime
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from click import ClickException
|
|
8
|
+
from cookiecutter.exceptions import OutputDirExistsException
|
|
9
|
+
from cookiecutter.main import cookiecutter
|
|
10
|
+
|
|
11
|
+
from shellfoundry.utilities.config_reader import CloudShellConfigReader, Configuration
|
|
12
|
+
from shellfoundry.utilities.constants import TEMPLATE_INFO_FILE
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CookiecutterTemplateCompiler(object):
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.cloudshell_config_reader = Configuration(CloudShellConfigReader())
|
|
18
|
+
|
|
19
|
+
def compile_template(
|
|
20
|
+
self,
|
|
21
|
+
shell_name,
|
|
22
|
+
template_path,
|
|
23
|
+
extra_context,
|
|
24
|
+
running_on_same_folder,
|
|
25
|
+
python_version=None,
|
|
26
|
+
):
|
|
27
|
+
|
|
28
|
+
if python_version is None:
|
|
29
|
+
python_version = ""
|
|
30
|
+
else:
|
|
31
|
+
python_version = ' PythonVersion="{}"'.format(str(python_version))
|
|
32
|
+
|
|
33
|
+
extra_context.update(
|
|
34
|
+
{
|
|
35
|
+
"project_name": shell_name,
|
|
36
|
+
"full_name": self.cloudshell_config_reader.read().author,
|
|
37
|
+
"release_date": datetime.datetime.now().strftime("%B %Y"),
|
|
38
|
+
"python_version": str(python_version),
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if running_on_same_folder:
|
|
43
|
+
output_dir = os.path.pardir
|
|
44
|
+
else:
|
|
45
|
+
output_dir = os.path.curdir
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
cookiecutter(
|
|
49
|
+
template_path,
|
|
50
|
+
no_input=True,
|
|
51
|
+
extra_context=extra_context,
|
|
52
|
+
overwrite_if_exists=False,
|
|
53
|
+
output_dir=output_dir,
|
|
54
|
+
)
|
|
55
|
+
except OutputDirExistsException as err:
|
|
56
|
+
if str(err).startswith("Error: "):
|
|
57
|
+
msg = str(err)[6:].strip()
|
|
58
|
+
else:
|
|
59
|
+
msg = str(err)
|
|
60
|
+
raise ClickException(msg)
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def _remove_template_info_file(shell_path):
|
|
64
|
+
"""Remove template info file from shell structure."""
|
|
65
|
+
template_info_file_path = os.path.join(shell_path, TEMPLATE_INFO_FILE)
|
|
66
|
+
if os.path.exists(template_info_file_path):
|
|
67
|
+
os.remove(template_info_file_path)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
try:
|
|
3
|
+
from urllib.error import URLError
|
|
4
|
+
except ImportError:
|
|
5
|
+
from urllib2 import URLError
|
|
6
|
+
|
|
7
|
+
import zipfile
|
|
8
|
+
from io import open
|
|
9
|
+
from os import path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from cloudshell.rest.api import PackagingRestApiClient
|
|
13
|
+
from requests import post
|
|
14
|
+
|
|
15
|
+
from shellfoundry.utilities.temp_dir_context import TempDirContext
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DriverGenerator(object):
|
|
19
|
+
def generate_driver(
|
|
20
|
+
self,
|
|
21
|
+
cloudshell_config,
|
|
22
|
+
destination_path,
|
|
23
|
+
package_full_path,
|
|
24
|
+
shell_filename,
|
|
25
|
+
shell_name,
|
|
26
|
+
):
|
|
27
|
+
"""Generates Python data model by connecting to Cloudshell server.
|
|
28
|
+
|
|
29
|
+
:param cloudshell_config:
|
|
30
|
+
:type cloudshell_config: InstallConfig
|
|
31
|
+
:param destination_path:
|
|
32
|
+
:param package_full_path:
|
|
33
|
+
:param shell_filename:
|
|
34
|
+
:param shell_name:
|
|
35
|
+
:return:
|
|
36
|
+
"""
|
|
37
|
+
client = self._connect_to_cloudshell(cloudshell_config)
|
|
38
|
+
self._generate_driver_data_model(
|
|
39
|
+
client=client,
|
|
40
|
+
cloudshell_config=cloudshell_config,
|
|
41
|
+
destination_path=destination_path,
|
|
42
|
+
package_full_path=package_full_path,
|
|
43
|
+
shell_filename=shell_filename,
|
|
44
|
+
shell_name=shell_name,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def _generate_driver_data_model(
|
|
49
|
+
client,
|
|
50
|
+
cloudshell_config,
|
|
51
|
+
destination_path,
|
|
52
|
+
package_full_path,
|
|
53
|
+
shell_filename,
|
|
54
|
+
shell_name,
|
|
55
|
+
):
|
|
56
|
+
"""Generates driver data model.
|
|
57
|
+
|
|
58
|
+
:param client:
|
|
59
|
+
:param cloudshell_config:
|
|
60
|
+
:type cloudshell_config: InstallConfig
|
|
61
|
+
:param destination_path:
|
|
62
|
+
:param package_full_path:
|
|
63
|
+
:param shell_filename:
|
|
64
|
+
:param shell_name:
|
|
65
|
+
:return:
|
|
66
|
+
"""
|
|
67
|
+
url = "http://{}:{}/API/ShellDrivers/Generate".format(
|
|
68
|
+
cloudshell_config.host, cloudshell_config.port
|
|
69
|
+
)
|
|
70
|
+
token = client.token
|
|
71
|
+
response = post(
|
|
72
|
+
url,
|
|
73
|
+
files={path.basename(shell_filename): open(package_full_path, "rb")},
|
|
74
|
+
headers={"Authorization": "Basic " + token},
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
if response.status_code != 200:
|
|
78
|
+
error_message = "Code generation failed with code {} and error {}".format(
|
|
79
|
+
response.status_code, response.text
|
|
80
|
+
)
|
|
81
|
+
click.echo(message=error_message, err=True)
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
click.echo("Extracting data model ...")
|
|
85
|
+
with TempDirContext(remove_dir_on_error=False, prefix=shell_name) as temp_dir:
|
|
86
|
+
generated_zip = path.join(temp_dir, shell_filename)
|
|
87
|
+
click.echo("Writing temporary file {}".format(generated_zip))
|
|
88
|
+
with open(generated_zip, "wb") as driver_file:
|
|
89
|
+
driver_file.write(response.content)
|
|
90
|
+
|
|
91
|
+
click.echo("Extracting generated code at {}".format(destination_path))
|
|
92
|
+
with zipfile.ZipFile(generated_zip) as zf:
|
|
93
|
+
zf.extractall(destination_path)
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def _connect_to_cloudshell(cloudshell_config):
|
|
97
|
+
try:
|
|
98
|
+
try:
|
|
99
|
+
client = PackagingRestApiClient.login(
|
|
100
|
+
host=cloudshell_config.host,
|
|
101
|
+
port=cloudshell_config.port,
|
|
102
|
+
username=cloudshell_config.username,
|
|
103
|
+
password=cloudshell_config.password,
|
|
104
|
+
domain=cloudshell_config.domain,
|
|
105
|
+
)
|
|
106
|
+
return client
|
|
107
|
+
except AttributeError:
|
|
108
|
+
client = PackagingRestApiClient(
|
|
109
|
+
ip=cloudshell_config.host,
|
|
110
|
+
port=cloudshell_config.port,
|
|
111
|
+
username=cloudshell_config.username,
|
|
112
|
+
password=cloudshell_config.password,
|
|
113
|
+
domain=cloudshell_config.domain,
|
|
114
|
+
)
|
|
115
|
+
return client
|
|
116
|
+
except URLError:
|
|
117
|
+
click.echo(
|
|
118
|
+
"Login to CloudShell failed. Please verify the credentials in cloudshell_config.yml", # noqa: E501
|
|
119
|
+
err=True,
|
|
120
|
+
)
|
|
121
|
+
raise
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
from . import (
|
|
4
|
+
GEN_ONE,
|
|
5
|
+
GEN_ONE_FILTER,
|
|
6
|
+
GEN_TWO,
|
|
7
|
+
GEN_TWO_FILTER,
|
|
8
|
+
LAYER_ONE,
|
|
9
|
+
LAYER_ONE_FILTER,
|
|
10
|
+
NO_FILTER,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CompositeFilter(object):
|
|
15
|
+
def __init__(self, template_type=None):
|
|
16
|
+
self.template_type = template_type or NO_FILTER
|
|
17
|
+
self.filters = {
|
|
18
|
+
GEN_ONE: GenOneFilter,
|
|
19
|
+
GEN_TWO: GenTwoFilter,
|
|
20
|
+
LAYER_ONE: LayerOneFilter,
|
|
21
|
+
NO_FILTER: NoFilter,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def filter(self, template_name): # noqa: A003
|
|
25
|
+
return self.filters.get(self.template_type, NoFilter)().filter(template_name)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GenOneFilter(object):
|
|
29
|
+
def filter(self, template_name): # noqa: A003
|
|
30
|
+
return GEN_ONE_FILTER in template_name
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class GenTwoFilter(object):
|
|
34
|
+
def filter(self, template_name): # noqa: A003
|
|
35
|
+
return GEN_TWO_FILTER in template_name
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class LayerOneFilter(object):
|
|
39
|
+
def filter(self, template_name): # noqa: A003
|
|
40
|
+
return LAYER_ONE_FILTER in template_name
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class NoFilter(object):
|
|
44
|
+
def filter(self, template_name): # noqa: A003
|
|
45
|
+
return True
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
from cloudshell.rest.api import PackagingRestApiClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ShellInstaller(object):
|
|
11
|
+
def install(self, package_name, config):
|
|
12
|
+
"""Installs package according to cloudshell.
|
|
13
|
+
|
|
14
|
+
:param package_name: Package name to install
|
|
15
|
+
:type package_name str
|
|
16
|
+
:param config: Configuration to be used for
|
|
17
|
+
:type config shellfoundry.models.install_config.InstallConfig
|
|
18
|
+
:return:
|
|
19
|
+
"""
|
|
20
|
+
package_full_path = os.path.join(os.getcwd(), "dist", package_name + ".zip")
|
|
21
|
+
click.echo(
|
|
22
|
+
"Installing package {} into CloudShell at http://{}:{}".format(
|
|
23
|
+
package_full_path, config.host, config.port
|
|
24
|
+
)
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
client = PackagingRestApiClient.login(
|
|
29
|
+
host=config.host,
|
|
30
|
+
port=config.port,
|
|
31
|
+
username=config.username,
|
|
32
|
+
password=config.password,
|
|
33
|
+
domain=config.domain,
|
|
34
|
+
)
|
|
35
|
+
except AttributeError:
|
|
36
|
+
client = PackagingRestApiClient(
|
|
37
|
+
ip=config.host,
|
|
38
|
+
port=config.port,
|
|
39
|
+
username=config.username,
|
|
40
|
+
password=config.password,
|
|
41
|
+
domain=config.domain,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
client.import_package(package_full_path)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from .password_modification import PasswordModification
|
|
5
|
+
|
|
6
|
+
DEFAULT_MODIFIER = (
|
|
7
|
+
lambda x: x
|
|
8
|
+
) # Default modifier returns the passed value unchanged # noqa: E731
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AggregatedModifiers(object):
|
|
12
|
+
def __init__(self, modifiers=None, default=None):
|
|
13
|
+
self.modifiers = modifiers or {
|
|
14
|
+
key: PasswordModification().modify
|
|
15
|
+
for key in PasswordModification.HANDLING_KEYS
|
|
16
|
+
}
|
|
17
|
+
self.default_modifier = default or AggregatedModifiers._default_modifier
|
|
18
|
+
|
|
19
|
+
def modify(self, key, value):
|
|
20
|
+
if key in self.modifiers:
|
|
21
|
+
return self.modifiers[key](value)
|
|
22
|
+
return self.default_modifier(value)
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def _default_modifier(value): # Default modifier returns the passed value unchanged
|
|
26
|
+
return value
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import base64
|
|
5
|
+
import binascii
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
import shellfoundry.exceptions as exceptions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PasswordModification(object):
|
|
12
|
+
HANDLING_KEYS = ["password", "github_password"]
|
|
13
|
+
|
|
14
|
+
def modify(self, value):
|
|
15
|
+
encryption_key = self._get_encryption_key()
|
|
16
|
+
encoded = self._decode_encode(value, encryption_key)
|
|
17
|
+
if sys.version_info[0] < 3:
|
|
18
|
+
return base64.b64encode(encoded)
|
|
19
|
+
else:
|
|
20
|
+
return base64.b64encode(encoded.encode()).decode()
|
|
21
|
+
|
|
22
|
+
def normalize(self, value):
|
|
23
|
+
try:
|
|
24
|
+
encryption_key = self._get_encryption_key()
|
|
25
|
+
if sys.version_info[0] < 3:
|
|
26
|
+
decoded = self._decode_encode(
|
|
27
|
+
base64.decodestring(value), encryption_key
|
|
28
|
+
)
|
|
29
|
+
else:
|
|
30
|
+
decoded = self._decode_encode(
|
|
31
|
+
base64.decodebytes(value.encode()).decode(), encryption_key
|
|
32
|
+
)
|
|
33
|
+
return decoded
|
|
34
|
+
except binascii.Error:
|
|
35
|
+
return value
|
|
36
|
+
|
|
37
|
+
def _get_encryption_key(self):
|
|
38
|
+
from platform import node
|
|
39
|
+
|
|
40
|
+
machine_name = node()
|
|
41
|
+
if not machine_name:
|
|
42
|
+
raise exceptions.PlatformNameIsEmptyException()
|
|
43
|
+
return machine_name
|
|
44
|
+
|
|
45
|
+
def _decode_encode(self, value, key):
|
|
46
|
+
return "".join(
|
|
47
|
+
chr(ord(source) ^ ord(key)) for source, key in zip(value, key * 100)
|
|
48
|
+
)
|
|
File without changes
|