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,52 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
from functools import update_wrapper
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from shellfoundry.exceptions import ShellFoundryVersionException
|
|
8
|
+
from shellfoundry.utilities import is_index_version_greater_than_current
|
|
9
|
+
from shellfoundry.utilities.config_reader import CloudShellConfigReader, Configuration
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class shellfoundry_version_check(object):
|
|
13
|
+
def __init__(self, abort_if_major=False):
|
|
14
|
+
self.abort_if_major = abort_if_major
|
|
15
|
+
self.cloudshell_config_reader = Configuration(CloudShellConfigReader())
|
|
16
|
+
|
|
17
|
+
def __call__(self, f):
|
|
18
|
+
def decorator(*args, **kwargs):
|
|
19
|
+
output = ""
|
|
20
|
+
if self.cloudshell_config_reader.read().online_mode.lower() == "true":
|
|
21
|
+
try:
|
|
22
|
+
(
|
|
23
|
+
is_greater_version,
|
|
24
|
+
is_major_release,
|
|
25
|
+
) = is_index_version_greater_than_current()
|
|
26
|
+
except ShellFoundryVersionException as err:
|
|
27
|
+
click.secho(str(err), fg="red")
|
|
28
|
+
raise click.Abort()
|
|
29
|
+
if is_greater_version:
|
|
30
|
+
if is_major_release:
|
|
31
|
+
output = (
|
|
32
|
+
"This version of shellfoundry is not supported anymore, "
|
|
33
|
+
"please upgrade by running: pip install shellfoundry --upgrade" # noqa: E501
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if self.abort_if_major:
|
|
37
|
+
click.secho(output, fg="yellow")
|
|
38
|
+
print("") # noqa: T001
|
|
39
|
+
raise click.Abort()
|
|
40
|
+
else:
|
|
41
|
+
output = (
|
|
42
|
+
"There is a new version of shellfoundry available, "
|
|
43
|
+
"please upgrade by running: pip install shellfoundry --upgrade" # noqa: E501
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
f(**kwargs)
|
|
47
|
+
|
|
48
|
+
if output:
|
|
49
|
+
print("") # noqa: T001
|
|
50
|
+
click.secho(output, fg="yellow")
|
|
51
|
+
|
|
52
|
+
return update_wrapper(decorator, f)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShellFoundryBaseException(Exception):
|
|
8
|
+
def __init__(self, message):
|
|
9
|
+
super(ShellFoundryBaseException, self).__init__(message)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ShellYmlMissingException(ShellFoundryBaseException):
|
|
13
|
+
def __init__(self, message):
|
|
14
|
+
super(ShellYmlMissingException, self).__init__(message)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WrongShellYmlException(ShellFoundryBaseException):
|
|
18
|
+
def __init__(self, message):
|
|
19
|
+
super(WrongShellYmlException, self).__init__(message)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class NoVersionsHaveBeenFoundException(ShellFoundryBaseException):
|
|
23
|
+
def __init__(self, message):
|
|
24
|
+
super(NoVersionsHaveBeenFoundException, self).__init__(message)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class VersionRequestException(ShellFoundryBaseException):
|
|
28
|
+
def __init__(self, message):
|
|
29
|
+
super(VersionRequestException, self).__init__(message)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class PlatformNameIsEmptyException(ShellFoundryBaseException):
|
|
33
|
+
def __init__(self, message="Machine name is empty"):
|
|
34
|
+
super(PlatformNameIsEmptyException, self).__init__(message)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class FatalError(click.ClickException):
|
|
38
|
+
def __init__(self, message):
|
|
39
|
+
super(FatalError, self).__init__(message)
|
|
40
|
+
|
|
41
|
+
def show(self, file=None):
|
|
42
|
+
click.secho("Error: {}".format(self.format_message()), err=True, fg="red")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class YmlFieldMissingException(Exception):
|
|
46
|
+
def __init__(self, message):
|
|
47
|
+
super(YmlFieldMissingException, self).__init__(message)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ShellFoundryVersionException(Exception):
|
|
51
|
+
def __init__(self, message):
|
|
52
|
+
super(ShellFoundryVersionException, self).__init__(message)
|
|
File without changes
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
|
|
3
|
+
from shellfoundry.utilities.modifiers.configuration.password_modification import (
|
|
4
|
+
PasswordModification,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
DEFAULT_HOST = "localhost"
|
|
8
|
+
DEFAULT_PORT = 9000
|
|
9
|
+
DEFAULT_USERNAME = "admin"
|
|
10
|
+
DEFAULT_PASSWORD = "admin"
|
|
11
|
+
DEFAULT_DOMAIN = "Global"
|
|
12
|
+
DEFAULT_AUTHOR = "Anonymous"
|
|
13
|
+
DEFAULT_ONLINE_MODE = "True"
|
|
14
|
+
DEFAULT_TEMPLATE_LOCATION = "Empty"
|
|
15
|
+
DEFAULT_GITHUB_LOGIN = ""
|
|
16
|
+
DEFAULT_GITHUB_PASSWORD = "gh_pass"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class InstallConfig(object):
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
host,
|
|
23
|
+
port,
|
|
24
|
+
username,
|
|
25
|
+
password,
|
|
26
|
+
domain,
|
|
27
|
+
author,
|
|
28
|
+
online_mode,
|
|
29
|
+
template_location,
|
|
30
|
+
github_login,
|
|
31
|
+
github_password,
|
|
32
|
+
):
|
|
33
|
+
self.domain = domain
|
|
34
|
+
self.password = self._decode_password(password)
|
|
35
|
+
self.username = username
|
|
36
|
+
self.port = port
|
|
37
|
+
self.host = host
|
|
38
|
+
self.author = author
|
|
39
|
+
self.online_mode = online_mode
|
|
40
|
+
self.template_location = template_location
|
|
41
|
+
self.github_login = github_login
|
|
42
|
+
self.github_password = self._decode_password(github_password)
|
|
43
|
+
|
|
44
|
+
def __eq__(self, other):
|
|
45
|
+
"""Comparison.
|
|
46
|
+
|
|
47
|
+
:param other: An instance of InstallConfig to compare
|
|
48
|
+
:type other InstallConfig
|
|
49
|
+
:return: True of same value, False otherwise
|
|
50
|
+
:rtype bool
|
|
51
|
+
"""
|
|
52
|
+
return (
|
|
53
|
+
self.domain == other.domain
|
|
54
|
+
and self.host == other.host
|
|
55
|
+
and self.password == other.password
|
|
56
|
+
and self.port == other.port
|
|
57
|
+
and self.username == other.username
|
|
58
|
+
and self.author == other.author
|
|
59
|
+
and self.online_mode == other.online_mode
|
|
60
|
+
and self.template_location == other.template_location
|
|
61
|
+
and self.github_login == other.github_login
|
|
62
|
+
and self.github_password == other.github_password
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def get_default():
|
|
67
|
+
return InstallConfig(
|
|
68
|
+
DEFAULT_HOST,
|
|
69
|
+
DEFAULT_PORT,
|
|
70
|
+
DEFAULT_USERNAME,
|
|
71
|
+
DEFAULT_PASSWORD,
|
|
72
|
+
DEFAULT_DOMAIN,
|
|
73
|
+
DEFAULT_AUTHOR,
|
|
74
|
+
DEFAULT_ONLINE_MODE,
|
|
75
|
+
DEFAULT_TEMPLATE_LOCATION,
|
|
76
|
+
DEFAULT_GITHUB_LOGIN,
|
|
77
|
+
DEFAULT_GITHUB_PASSWORD,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def _decode_password(self, password):
|
|
81
|
+
pass_mod = PasswordModification()
|
|
82
|
+
return pass_mod.normalize(password)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ShellTemplate(object):
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
name,
|
|
9
|
+
description,
|
|
10
|
+
repository,
|
|
11
|
+
min_cs_ver,
|
|
12
|
+
standard=None,
|
|
13
|
+
standard_version=None,
|
|
14
|
+
params=None,
|
|
15
|
+
):
|
|
16
|
+
self.name = name
|
|
17
|
+
self.description = description
|
|
18
|
+
self.repository = repository
|
|
19
|
+
self.min_cs_ver = min_cs_ver
|
|
20
|
+
self.standard = standard
|
|
21
|
+
self.standard_version = standard_version or {}
|
|
22
|
+
self.params = params or {}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
DEFAULT_DEFAULT_VIEW = "gen2"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShellFoundrySettings(object):
|
|
8
|
+
def __init__(self, defaultview):
|
|
9
|
+
self.defaultview = defaultview
|
|
10
|
+
|
|
11
|
+
@staticmethod
|
|
12
|
+
def get_default():
|
|
13
|
+
return ShellFoundrySettings(DEFAULT_DEFAULT_VIEW)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import ssl
|
|
6
|
+
|
|
7
|
+
import pkg_resources
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
# Python 2.x version
|
|
11
|
+
from xmlrpclib import ProtocolError, ServerProxy
|
|
12
|
+
except ImportError:
|
|
13
|
+
# Python 3.x version
|
|
14
|
+
from xmlrpc.client import ProtocolError, ServerProxy
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
from urllib import urlopen
|
|
18
|
+
except ImportError:
|
|
19
|
+
from urllib.request import urlopen
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
from urllib.error import HTTPError, URLError
|
|
23
|
+
except ImportError:
|
|
24
|
+
from urllib2 import HTTPError, URLError
|
|
25
|
+
|
|
26
|
+
from distutils.version import StrictVersion
|
|
27
|
+
|
|
28
|
+
from shellfoundry import PACKAGE_NAME
|
|
29
|
+
from shellfoundry.exceptions import ShellFoundryVersionException
|
|
30
|
+
|
|
31
|
+
GEN_ONE = "gen1"
|
|
32
|
+
GEN_TWO = "gen2"
|
|
33
|
+
LAYER_ONE = "layer1"
|
|
34
|
+
NO_FILTER = "all"
|
|
35
|
+
GEN_ONE_FILTER = "gen1"
|
|
36
|
+
GEN_TWO_FILTER = "gen2"
|
|
37
|
+
LAYER_ONE_FILTER = "layer-1"
|
|
38
|
+
SEPARATOR = "/"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Index(object):
|
|
42
|
+
def __init__(self, url):
|
|
43
|
+
self.url = url
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
PyPI = Index("https://pypi.python.org/pypi/")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_installed_version(package_name):
|
|
50
|
+
return pkg_resources.get_distribution(package_name).version
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def is_index_version_greater_than_current():
|
|
54
|
+
MAJOR_INDEX = 0
|
|
55
|
+
|
|
56
|
+
installed, index = (
|
|
57
|
+
StrictVersion(get_installed_version(PACKAGE_NAME)),
|
|
58
|
+
StrictVersion(max_version_from_index()),
|
|
59
|
+
)
|
|
60
|
+
is_major_release = False
|
|
61
|
+
|
|
62
|
+
is_greater_version = index > installed
|
|
63
|
+
if (
|
|
64
|
+
is_greater_version
|
|
65
|
+
and get_index_of_biggest_component_between_two_versions(
|
|
66
|
+
index.version, installed.version
|
|
67
|
+
)
|
|
68
|
+
== MAJOR_INDEX
|
|
69
|
+
):
|
|
70
|
+
is_major_release = True
|
|
71
|
+
|
|
72
|
+
return is_greater_version, is_major_release
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def max_version_from_index():
|
|
76
|
+
try:
|
|
77
|
+
ctx = ssl.SSLContext(protocol=ssl.PROTOCOL_SSLv23)
|
|
78
|
+
proxy = ServerProxy(PyPI.url, context=ctx)
|
|
79
|
+
releases = proxy.package_releases(PACKAGE_NAME)
|
|
80
|
+
max_version = max(releases)
|
|
81
|
+
return max_version
|
|
82
|
+
except ProtocolError as err:
|
|
83
|
+
raise ShellFoundryVersionException(
|
|
84
|
+
"Cannot retrieve latest shellfoundry version, "
|
|
85
|
+
"are you offline? Error: {}".format(err)
|
|
86
|
+
)
|
|
87
|
+
except Exception as err:
|
|
88
|
+
raise ShellFoundryVersionException(
|
|
89
|
+
"Unexpected error during shellfoundry version check. "
|
|
90
|
+
"Error: {}.".format(err)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def latest_released_version():
|
|
95
|
+
url = "https://pypi.org/pypi/{package_name}/json"
|
|
96
|
+
try:
|
|
97
|
+
package_info = json.load(urlopen(url.format(package_name=PACKAGE_NAME)))
|
|
98
|
+
return package_info["info"]["version"]
|
|
99
|
+
except (HTTPError, URLError) as err:
|
|
100
|
+
raise ShellFoundryVersionException(
|
|
101
|
+
"Cannot retrieve latest shellfoundry version, "
|
|
102
|
+
"are you offline? Error: {}".format(err)
|
|
103
|
+
)
|
|
104
|
+
except Exception as err:
|
|
105
|
+
raise ShellFoundryVersionException(
|
|
106
|
+
"Unexpected error during shellfoundry version check. "
|
|
107
|
+
"Error: {}.".format(err)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_index_of_biggest_component_between_two_versions(v1, v2):
|
|
112
|
+
for i in range(0, len(v1)):
|
|
113
|
+
if v1[i] > v2[i]:
|
|
114
|
+
return i
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import zipfile
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ArchiveCreator(object):
|
|
6
|
+
@staticmethod
|
|
7
|
+
def make_archive(output_filename, archive_format, source_dir):
|
|
8
|
+
"""Creates archive in specified format recursively of source_dir.
|
|
9
|
+
|
|
10
|
+
Replaces shutil.make_archive in order to be able to test with pyfakefs
|
|
11
|
+
:param output_filename: Output archive file name.
|
|
12
|
+
If directory does not exist, it will be created
|
|
13
|
+
:param archive_format: Archive format to be used.
|
|
14
|
+
Currently only zip is supported
|
|
15
|
+
:param source_dir: Directory to scan for archiving
|
|
16
|
+
:return:
|
|
17
|
+
"""
|
|
18
|
+
if os.path.exists(source_dir):
|
|
19
|
+
if os.path.splitext(output_filename)[1] == "":
|
|
20
|
+
output_filename += ".zip"
|
|
21
|
+
output_dir = os.path.dirname(output_filename)
|
|
22
|
+
if output_dir and not os.path.exists(output_dir):
|
|
23
|
+
os.makedirs(output_dir)
|
|
24
|
+
relroot = source_dir
|
|
25
|
+
with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as zip_f:
|
|
26
|
+
for root, dirs, files in os.walk(source_dir):
|
|
27
|
+
# add directory (needed for empty dirs)
|
|
28
|
+
zip_f.write(root, os.path.relpath(root, relroot))
|
|
29
|
+
for file in files:
|
|
30
|
+
filename = os.path.join(root, file)
|
|
31
|
+
if os.path.isfile(filename): # regular files only
|
|
32
|
+
arcname = os.path.join(os.path.relpath(root, relroot), file)
|
|
33
|
+
zip_f.write(filename, arcname)
|
|
34
|
+
|
|
35
|
+
return output_filename
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .client_wrapper import CloudShellClient, create_cloudshell_client # noqa: F401
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
|
|
3
|
+
from cloudshell.rest.api import PackagingRestApiClient
|
|
4
|
+
|
|
5
|
+
from shellfoundry.exceptions import FatalError
|
|
6
|
+
from shellfoundry.utilities.config_reader import CloudShellConfigReader, Configuration
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from urllib.error import HTTPError
|
|
10
|
+
except Exception:
|
|
11
|
+
from urllib2 import HTTPError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_cloudshell_client(retries=1):
|
|
15
|
+
try:
|
|
16
|
+
cs_client = CloudShellClient().create_client(retries=retries)
|
|
17
|
+
except FatalError:
|
|
18
|
+
raise
|
|
19
|
+
return cs_client
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CloudShellClient(object):
|
|
23
|
+
ConnectionFailureMessage = "Connection to CloudShell Server failed. Please make sure it is up and running properly." # noqa: E501
|
|
24
|
+
|
|
25
|
+
def __init__(self, cs_config=None):
|
|
26
|
+
"""Creates cloudshell client.
|
|
27
|
+
|
|
28
|
+
:type cs_config shellfoundry.models.install_config.InstallConfig
|
|
29
|
+
"""
|
|
30
|
+
self._cs_config = cs_config or Configuration(CloudShellConfigReader()).read()
|
|
31
|
+
|
|
32
|
+
def create_client(self, **kwargs):
|
|
33
|
+
retries = kwargs.get("retries", 1)
|
|
34
|
+
if retries == 0:
|
|
35
|
+
raise FatalError(self.ConnectionFailureMessage)
|
|
36
|
+
try:
|
|
37
|
+
return self._create_client()
|
|
38
|
+
except FatalError as e:
|
|
39
|
+
retry = retries - 1
|
|
40
|
+
if retry == 0:
|
|
41
|
+
raise e
|
|
42
|
+
return self.create_client(retries=retry)
|
|
43
|
+
|
|
44
|
+
def _create_client(self):
|
|
45
|
+
try:
|
|
46
|
+
try:
|
|
47
|
+
client = PackagingRestApiClient.login(
|
|
48
|
+
host=self._cs_config.host,
|
|
49
|
+
port=self._cs_config.port,
|
|
50
|
+
username=self._cs_config.username,
|
|
51
|
+
password=self._cs_config.password,
|
|
52
|
+
domain=self._cs_config.domain,
|
|
53
|
+
)
|
|
54
|
+
return client
|
|
55
|
+
except AttributeError:
|
|
56
|
+
client = PackagingRestApiClient(
|
|
57
|
+
ip=self._cs_config.host,
|
|
58
|
+
port=self._cs_config.port,
|
|
59
|
+
username=self._cs_config.username,
|
|
60
|
+
password=self._cs_config.password,
|
|
61
|
+
domain=self._cs_config.domain,
|
|
62
|
+
)
|
|
63
|
+
return client
|
|
64
|
+
except (HTTPError, Exception) as e:
|
|
65
|
+
if hasattr(e, "code") and e.code == 401:
|
|
66
|
+
if hasattr(e, "msg") and e.msg:
|
|
67
|
+
msg = e.msg
|
|
68
|
+
else:
|
|
69
|
+
msg = "Please verify the credentials in the config"
|
|
70
|
+
raise FatalError("Login to CloudShell failed. {}".format(msg))
|
|
71
|
+
raise FatalError(self.ConnectionFailureMessage)
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# !/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from io import open
|
|
5
|
+
|
|
6
|
+
import yaml
|
|
7
|
+
|
|
8
|
+
from shellfoundry.utilities.config_reader import INSTALL
|
|
9
|
+
from shellfoundry.utilities.modifiers.configuration.aggregated_modifiers import (
|
|
10
|
+
AggregatedModifiers,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ConfigContext(object):
|
|
15
|
+
def __init__(self, config_file_path):
|
|
16
|
+
self.config_file_path = config_file_path
|
|
17
|
+
self.modifier = AggregatedModifiers()
|
|
18
|
+
|
|
19
|
+
def try_save(self, key, value):
|
|
20
|
+
try:
|
|
21
|
+
with open(self.config_file_path, mode="r+", encoding="utf8") as stream:
|
|
22
|
+
data = yaml.safe_load(stream) or {INSTALL: {}}
|
|
23
|
+
data[INSTALL][key] = self._modify(key, value)
|
|
24
|
+
stream.seek(0)
|
|
25
|
+
stream.truncate()
|
|
26
|
+
yaml.safe_dump(data, stream=stream, default_flow_style=False)
|
|
27
|
+
return True
|
|
28
|
+
except Exception:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
def try_delete(self, key):
|
|
32
|
+
try:
|
|
33
|
+
with open(self.config_file_path, mode="r+", encoding="utf8") as stream:
|
|
34
|
+
data = yaml.safe_load(stream)
|
|
35
|
+
del data[INSTALL][key] # handle cases that INSTALL does not exists
|
|
36
|
+
stream.seek(0)
|
|
37
|
+
stream.truncate()
|
|
38
|
+
yaml.safe_dump(data, stream=stream, default_flow_style=False)
|
|
39
|
+
return True
|
|
40
|
+
except Exception:
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
def _modify(self, key, value):
|
|
44
|
+
return self.modifier.modify(key, value)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
import errno
|
|
4
|
+
import os
|
|
5
|
+
from io import open
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ConfigFileCreation(object):
|
|
11
|
+
def create(self, config_file_path):
|
|
12
|
+
if os.path.exists(config_file_path):
|
|
13
|
+
return
|
|
14
|
+
if not os.path.exists(os.path.dirname(config_file_path)):
|
|
15
|
+
try:
|
|
16
|
+
dirname = os.path.dirname(config_file_path)
|
|
17
|
+
os.makedirs(dirname)
|
|
18
|
+
except OSError as exc:
|
|
19
|
+
if exc.errno != errno.EEXIST:
|
|
20
|
+
click.echo("Failed to create config file")
|
|
21
|
+
click.echo(str(exc))
|
|
22
|
+
raise
|
|
23
|
+
try:
|
|
24
|
+
click.echo("Creating config file...")
|
|
25
|
+
open(config_file_path, mode="w", encoding="utf8").close()
|
|
26
|
+
except Exception:
|
|
27
|
+
if not os.path.exists(config_file_path):
|
|
28
|
+
click.echo("Failed to create config file")
|
|
29
|
+
import sys
|
|
30
|
+
|
|
31
|
+
click.echo(str(sys.exc_info()[1]))
|
|
32
|
+
raise
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
GLOBAL_CONFIG_NAME = "global_config.yml"
|
|
9
|
+
LOCAL_CONFIG_NAME = "cloudshell_config.yml"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LocalConfigProvider(object):
|
|
13
|
+
def get_config_path(self):
|
|
14
|
+
path = os.path.join(os.getcwd(), LOCAL_CONFIG_NAME)
|
|
15
|
+
if os.path.exists(path):
|
|
16
|
+
click.echo("Using local configuration...")
|
|
17
|
+
return path
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GlobalConfigProvider(object):
|
|
21
|
+
QUALI = "Quali"
|
|
22
|
+
PRODUCT = "shellfoundry"
|
|
23
|
+
|
|
24
|
+
def get_config_path(self):
|
|
25
|
+
sf_name = os.path.join(GlobalConfigProvider.QUALI, GlobalConfigProvider.PRODUCT)
|
|
26
|
+
app_dir_path = click.get_app_dir(sf_name)
|
|
27
|
+
return os.path.join(app_dir_path, GLOBAL_CONFIG_NAME)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ConfigProvider(object):
|
|
31
|
+
def __init__(self, *args):
|
|
32
|
+
self.config_providers = args
|
|
33
|
+
|
|
34
|
+
def get_config_path(self):
|
|
35
|
+
for provider in self.config_providers:
|
|
36
|
+
config_path = provider.get_config_path()
|
|
37
|
+
if os.path.exists(config_path):
|
|
38
|
+
return config_path
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class DefaultConfigProvider(ConfigProvider):
|
|
42
|
+
def __init__(self):
|
|
43
|
+
ConfigProvider.__init__(self, (GlobalConfigProvider())) # The order do matters
|
|
44
|
+
self.default_provider = LocalConfigProvider()
|
|
45
|
+
|
|
46
|
+
def get_config_path(self):
|
|
47
|
+
config_path = self.default_provider.get_config_path()
|
|
48
|
+
if not os.path.exists(config_path):
|
|
49
|
+
config_path = ConfigProvider.get_config_path(self)
|
|
50
|
+
return config_path # or self.fallback_provider.get_config_path()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ConfigRecord(object):
|
|
8
|
+
def __init__(self, key, value=None):
|
|
9
|
+
self.key = key
|
|
10
|
+
self.value = value
|
|
11
|
+
|
|
12
|
+
def save(self, config_context):
|
|
13
|
+
if config_context.try_save(self.key, self.value):
|
|
14
|
+
click.echo("{}: {} was saved successfully".format(self.key, self.value))
|
|
15
|
+
else:
|
|
16
|
+
click.echo("Failed to save key value")
|
|
17
|
+
|
|
18
|
+
def delete(self, config_context):
|
|
19
|
+
if config_context.try_delete(self.key):
|
|
20
|
+
click.echo("{} was deleted successfully".format(self.key))
|
|
21
|
+
else:
|
|
22
|
+
# add support for typed exceptions
|
|
23
|
+
# in order to have the ability to differentiate between failures
|
|
24
|
+
click.echo("Failed to delete key")
|