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,393 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from io import open
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from cloudshell.rest.exceptions import FeatureUnavailable
|
|
11
|
+
from pkg_resources import parse_version
|
|
12
|
+
from requests.exceptions import SSLError
|
|
13
|
+
|
|
14
|
+
from ..exceptions import FatalError
|
|
15
|
+
|
|
16
|
+
from shellfoundry import (
|
|
17
|
+
ALTERNATIVE_STANDARDS_PATH,
|
|
18
|
+
ALTERNATIVE_TEMPLATES_PATH,
|
|
19
|
+
MASTER_BRANCH_NAME,
|
|
20
|
+
)
|
|
21
|
+
from shellfoundry.exceptions import VersionRequestException
|
|
22
|
+
from shellfoundry.utilities.config_reader import CloudShellConfigReader, Configuration
|
|
23
|
+
from shellfoundry.utilities.constants import TEMPLATE_INFO_FILE
|
|
24
|
+
from shellfoundry.utilities.cookiecutter_integration import CookiecutterTemplateCompiler
|
|
25
|
+
from shellfoundry.utilities.repository_downloader import RepositoryDownloader
|
|
26
|
+
from shellfoundry.utilities.standards import Standards, StandardVersionsFactory
|
|
27
|
+
from shellfoundry.utilities.temp_dir_context import TempDirContext
|
|
28
|
+
from shellfoundry.utilities.template_retriever import TemplateRetriever
|
|
29
|
+
from shellfoundry.utilities.template_versions import TemplateVersions
|
|
30
|
+
from shellfoundry.utilities.validations import ShellNameValidations
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class NewCommandExecutor(object):
|
|
34
|
+
LOCAL_TEMPLATE_URL_PREFIX = "local:"
|
|
35
|
+
REMOTE_TEMPLATE_URL_PREFIX = "url:"
|
|
36
|
+
L1_TEMPLATE = "layer-1-switch"
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
template_compiler=None,
|
|
41
|
+
template_retriever=None,
|
|
42
|
+
repository_downloader=None,
|
|
43
|
+
standards=None,
|
|
44
|
+
standard_versions=None,
|
|
45
|
+
shell_name_validations=None,
|
|
46
|
+
):
|
|
47
|
+
"""Creates shell based on template and standards.
|
|
48
|
+
|
|
49
|
+
:param CookiecutterTemplateCompiler template_compiler:
|
|
50
|
+
:param TemplateRetriever template_retriever:
|
|
51
|
+
:param RepositoryDownloader repository_downloader:
|
|
52
|
+
:param Standards standards:
|
|
53
|
+
:param StandardVersionsFactory standard_versions:
|
|
54
|
+
:param ShellNameValidations shell_name_validations:
|
|
55
|
+
"""
|
|
56
|
+
self.cloudshell_config_reader = Configuration(CloudShellConfigReader())
|
|
57
|
+
self.template_retriever = template_retriever or TemplateRetriever()
|
|
58
|
+
self.repository_downloader = repository_downloader or RepositoryDownloader()
|
|
59
|
+
self.template_compiler = template_compiler or CookiecutterTemplateCompiler()
|
|
60
|
+
self.standards = standards or Standards()
|
|
61
|
+
self.standard_versions = standard_versions or StandardVersionsFactory()
|
|
62
|
+
self.shell_name_validations = shell_name_validations or ShellNameValidations()
|
|
63
|
+
|
|
64
|
+
def new(self, name, template, version=None, python_version="3"):
|
|
65
|
+
"""Create a new shell based on a template.
|
|
66
|
+
|
|
67
|
+
:param str version: The desired version of the shell template to use
|
|
68
|
+
:param str name: The name of the Shell
|
|
69
|
+
:param str template: The name of the template to use
|
|
70
|
+
:param str python_version: Python version
|
|
71
|
+
"""
|
|
72
|
+
# Special handling for the case where the user runs 'shellfoundry .'
|
|
73
|
+
# in such a case the '.' character is substituted for the shell name
|
|
74
|
+
# and the content of the current folder is populated
|
|
75
|
+
running_on_same_folder = False
|
|
76
|
+
if name == os.path.curdir:
|
|
77
|
+
name = os.path.split(os.getcwd())[1]
|
|
78
|
+
running_on_same_folder = True
|
|
79
|
+
|
|
80
|
+
if not self.shell_name_validations.validate_shell_name(name):
|
|
81
|
+
raise click.BadParameter(
|
|
82
|
+
"Shell name must begin with a letter "
|
|
83
|
+
"and contain only alpha-numeric characters and spaces."
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
standards = self.standards.fetch()
|
|
88
|
+
except FeatureUnavailable:
|
|
89
|
+
standards = self.standards.fetch(alternative=ALTERNATIVE_STANDARDS_PATH)
|
|
90
|
+
except Exception as err:
|
|
91
|
+
raise click.ClickException(
|
|
92
|
+
"Cannot retrieve standards list. Error: {}".format(err)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Get template using direct url path. Ignore parameter in configuration file
|
|
96
|
+
if self._is_direct_online_template(template):
|
|
97
|
+
self._import_direct_online_template(
|
|
98
|
+
name, running_on_same_folder, template, standards, python_version
|
|
99
|
+
)
|
|
100
|
+
# Get template using direct path. Ignore parameter in configuration file
|
|
101
|
+
elif self._is_direct_local_template(template):
|
|
102
|
+
self._import_local_template(
|
|
103
|
+
name, running_on_same_folder, template, standards, python_version
|
|
104
|
+
)
|
|
105
|
+
# Get template from GitHub repository
|
|
106
|
+
elif self.cloudshell_config_reader.read().online_mode.lower() == "true":
|
|
107
|
+
self._import_online_template(
|
|
108
|
+
name,
|
|
109
|
+
running_on_same_folder,
|
|
110
|
+
template,
|
|
111
|
+
version,
|
|
112
|
+
standards,
|
|
113
|
+
python_version,
|
|
114
|
+
)
|
|
115
|
+
# Get template from location defined in shellfoundry configuration
|
|
116
|
+
else:
|
|
117
|
+
template = self._get_local_template_full_path(template, standards, version)
|
|
118
|
+
self._import_local_template(
|
|
119
|
+
name, running_on_same_folder, template, standards, python_version
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
if template == self.L1_TEMPLATE:
|
|
123
|
+
click.secho("WARNING: L1 shells support python 2.7 only!", fg="yellow")
|
|
124
|
+
|
|
125
|
+
click.echo("Created shell {0} based on template {1}".format(name, template))
|
|
126
|
+
|
|
127
|
+
def _import_direct_online_template(
|
|
128
|
+
self, name, running_on_same_folder, template, standards, python_version
|
|
129
|
+
):
|
|
130
|
+
"""Create shell based on template downloaded by the direct link."""
|
|
131
|
+
template_url = self._remove_prefix(
|
|
132
|
+
template, NewCommandExecutor.REMOTE_TEMPLATE_URL_PREFIX
|
|
133
|
+
)
|
|
134
|
+
with TempDirContext(name) as temp_dir:
|
|
135
|
+
try:
|
|
136
|
+
repo_path = self.repository_downloader.download_template(
|
|
137
|
+
temp_dir, template_url, branch=None, is_need_construct=False
|
|
138
|
+
)
|
|
139
|
+
except VersionRequestException:
|
|
140
|
+
raise click.BadParameter(
|
|
141
|
+
"Failed to download template from provided direct link {}".format(
|
|
142
|
+
template_url
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
self._verify_template_standards_compatibility(
|
|
147
|
+
template_path=repo_path, standards=standards
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
extra_content = self._get_template_params(repo_path=repo_path)
|
|
151
|
+
|
|
152
|
+
self.template_compiler.compile_template(
|
|
153
|
+
shell_name=name,
|
|
154
|
+
template_path=repo_path,
|
|
155
|
+
extra_context=extra_content,
|
|
156
|
+
running_on_same_folder=running_on_same_folder,
|
|
157
|
+
python_version=python_version,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
def _import_online_template(
|
|
161
|
+
self, name, running_on_same_folder, template, version, standards, python_version
|
|
162
|
+
):
|
|
163
|
+
"""Create shell based on template downloaded from GitHub by the name."""
|
|
164
|
+
# Create a temp folder for the operation to make sure we delete it after
|
|
165
|
+
with TempDirContext(name) as temp_dir:
|
|
166
|
+
try:
|
|
167
|
+
templates = self.template_retriever.get_templates(standards=standards)
|
|
168
|
+
except (SSLError, FatalError):
|
|
169
|
+
raise click.UsageError(
|
|
170
|
+
"Cannot retrieve templates list, are you offline?"
|
|
171
|
+
)
|
|
172
|
+
except FeatureUnavailable:
|
|
173
|
+
templates = self.template_retriever.get_templates(
|
|
174
|
+
alternative=ALTERNATIVE_TEMPLATES_PATH, standards=standards
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
templates = {
|
|
178
|
+
template_name: template[0]
|
|
179
|
+
for template_name, template in templates.items()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if template not in templates:
|
|
183
|
+
raise click.BadParameter(
|
|
184
|
+
"Template {0} does not exist. "
|
|
185
|
+
"Supported templates are: {1}".format(
|
|
186
|
+
template, self._get_templates_with_comma(templates)
|
|
187
|
+
)
|
|
188
|
+
)
|
|
189
|
+
template_obj = templates[template]
|
|
190
|
+
|
|
191
|
+
if not version and template != self.L1_TEMPLATE:
|
|
192
|
+
version = self._get_template_latest_version(
|
|
193
|
+
standards, template_obj.standard
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
repo_path = self.repository_downloader.download_template(
|
|
198
|
+
temp_dir, template_obj.repository, version
|
|
199
|
+
)
|
|
200
|
+
except VersionRequestException:
|
|
201
|
+
branches = TemplateVersions(
|
|
202
|
+
*template_obj.repository.split("/")[-2:]
|
|
203
|
+
).get_versions_of_template()
|
|
204
|
+
branches.remove(MASTER_BRANCH_NAME)
|
|
205
|
+
branches_str = ", ".join(branches)
|
|
206
|
+
raise click.BadParameter(
|
|
207
|
+
"Requested standard version ('{}') doesn't match template version."
|
|
208
|
+
" \nAvailable versions for {}: {}".format(
|
|
209
|
+
version, template_obj.name, branches_str
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
self._verify_template_standards_compatibility(
|
|
214
|
+
template_path=repo_path, standards=standards
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
self.template_compiler.compile_template(
|
|
218
|
+
shell_name=name,
|
|
219
|
+
template_path=repo_path,
|
|
220
|
+
extra_context=template_obj.params,
|
|
221
|
+
running_on_same_folder=running_on_same_folder,
|
|
222
|
+
python_version=python_version,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
def _import_local_template(
|
|
226
|
+
self, name, running_on_same_folder, template, standards, python_version
|
|
227
|
+
):
|
|
228
|
+
"""Create shell based on direct path to local template."""
|
|
229
|
+
repo_path = self._remove_prefix(
|
|
230
|
+
template, NewCommandExecutor.LOCAL_TEMPLATE_URL_PREFIX
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
if not os.path.exists(repo_path) or not os.path.isdir(repo_path):
|
|
234
|
+
raise click.BadParameter(
|
|
235
|
+
"Could not locate a template folder at: {template_path}".format(
|
|
236
|
+
template_path=repo_path
|
|
237
|
+
)
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
extra_content = self._get_template_params(repo_path=repo_path)
|
|
241
|
+
|
|
242
|
+
self._verify_template_standards_compatibility(
|
|
243
|
+
template_path=repo_path, standards=standards
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
self.template_compiler.compile_template(
|
|
247
|
+
shell_name=name,
|
|
248
|
+
template_path=repo_path,
|
|
249
|
+
extra_context=extra_content,
|
|
250
|
+
running_on_same_folder=running_on_same_folder,
|
|
251
|
+
python_version=python_version,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def _get_template_latest_version(self, standards_list, standard):
|
|
255
|
+
try:
|
|
256
|
+
return self.standard_versions.create(standards_list).get_latest_version(
|
|
257
|
+
standard
|
|
258
|
+
)
|
|
259
|
+
except Exception as e:
|
|
260
|
+
click.ClickException(str(e))
|
|
261
|
+
|
|
262
|
+
def _get_local_template_full_path(self, template_name, standards, version=None):
|
|
263
|
+
"""Get full path to local template based on provided template name."""
|
|
264
|
+
templates_location = self.cloudshell_config_reader.read().template_location
|
|
265
|
+
|
|
266
|
+
templates = self.template_retriever.get_templates(
|
|
267
|
+
template_location=templates_location, standards=standards
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
template_obj = templates.get(template_name, None)
|
|
271
|
+
if template_obj is None:
|
|
272
|
+
raise click.BadParameter(
|
|
273
|
+
"There is no template with name ({tmpl_name}).\n"
|
|
274
|
+
"Please, run command 'shellfoundry list' "
|
|
275
|
+
"to get all available templates.".format(tmpl_name=template_name)
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
avail_standards = set()
|
|
279
|
+
avail_templates = {}
|
|
280
|
+
for template in template_obj:
|
|
281
|
+
avail_standards.update(standards[template.standard])
|
|
282
|
+
avail_templates.update(template.standard_version)
|
|
283
|
+
|
|
284
|
+
if version:
|
|
285
|
+
if version in avail_standards:
|
|
286
|
+
if version in avail_templates:
|
|
287
|
+
return avail_templates[version]["repo"]
|
|
288
|
+
else:
|
|
289
|
+
raise click.BadParameter(
|
|
290
|
+
"Requested template version ({version}) "
|
|
291
|
+
"does not exist at templates location ({path}).\n"
|
|
292
|
+
"Existing template versions: {existing_versions}".format(
|
|
293
|
+
version=version,
|
|
294
|
+
path=templates_location,
|
|
295
|
+
existing_versions=", ".join(list(avail_templates.keys())),
|
|
296
|
+
)
|
|
297
|
+
)
|
|
298
|
+
else:
|
|
299
|
+
raise click.BadParameter(
|
|
300
|
+
"Requested template version ({version}) "
|
|
301
|
+
"does not compatible with available Standards on CloudShell Server"
|
|
302
|
+
" ({avail_standards})".format(
|
|
303
|
+
version=version, avail_standards=", ".join(avail_standards)
|
|
304
|
+
)
|
|
305
|
+
)
|
|
306
|
+
else:
|
|
307
|
+
# try to find max available template version
|
|
308
|
+
try:
|
|
309
|
+
version = str(
|
|
310
|
+
max(
|
|
311
|
+
list(
|
|
312
|
+
map(
|
|
313
|
+
parse_version,
|
|
314
|
+
avail_standards & set(avail_templates.keys()),
|
|
315
|
+
)
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
)
|
|
319
|
+
except ValueError:
|
|
320
|
+
raise click.ClickException("There are no compatible templates and ")
|
|
321
|
+
|
|
322
|
+
return avail_templates[version]["repo"]
|
|
323
|
+
|
|
324
|
+
@staticmethod
|
|
325
|
+
def _get_template_params(repo_path):
|
|
326
|
+
"""Determine template additional parameters."""
|
|
327
|
+
full_path = os.path.join(repo_path, TEMPLATE_INFO_FILE)
|
|
328
|
+
if not os.path.exists(full_path):
|
|
329
|
+
raise click.ClickException(
|
|
330
|
+
"Wrong template path provided. Provided path: {}".format(repo_path)
|
|
331
|
+
)
|
|
332
|
+
with open(full_path, mode="r", encoding="utf8") as f:
|
|
333
|
+
templ_data = json.load(f)
|
|
334
|
+
|
|
335
|
+
family_name = templ_data.get("family_name")
|
|
336
|
+
if isinstance(family_name, list):
|
|
337
|
+
value = click.prompt(
|
|
338
|
+
"Please, choose one of the possible family name: {}".format(
|
|
339
|
+
", ".join(family_name)
|
|
340
|
+
),
|
|
341
|
+
default=family_name[0],
|
|
342
|
+
)
|
|
343
|
+
if value not in family_name:
|
|
344
|
+
raise click.UsageError("Incorrect family name provided.")
|
|
345
|
+
extra_context = {"family_name": value}
|
|
346
|
+
elif family_name:
|
|
347
|
+
extra_context = {"family_name": family_name}
|
|
348
|
+
else:
|
|
349
|
+
extra_context = {}
|
|
350
|
+
|
|
351
|
+
return extra_context
|
|
352
|
+
|
|
353
|
+
@staticmethod
|
|
354
|
+
def _is_direct_local_template(template):
|
|
355
|
+
return template.startswith(NewCommandExecutor.LOCAL_TEMPLATE_URL_PREFIX)
|
|
356
|
+
|
|
357
|
+
@staticmethod
|
|
358
|
+
def _is_direct_online_template(template):
|
|
359
|
+
return template.startswith(NewCommandExecutor.REMOTE_TEMPLATE_URL_PREFIX)
|
|
360
|
+
|
|
361
|
+
@staticmethod
|
|
362
|
+
def _remove_prefix(string, prefix):
|
|
363
|
+
return string.rpartition(prefix)[-1]
|
|
364
|
+
|
|
365
|
+
@staticmethod
|
|
366
|
+
def _get_templates_with_comma(templates):
|
|
367
|
+
return ", ".join(list(templates.keys()))
|
|
368
|
+
|
|
369
|
+
@staticmethod
|
|
370
|
+
def _verify_template_standards_compatibility(template_path, standards):
|
|
371
|
+
"""Check is template and available standards on cloudshell are compatible."""
|
|
372
|
+
shell_def_path = os.path.join(
|
|
373
|
+
template_path, "{{cookiecutter.project_slug}}", "shell-definition.yaml"
|
|
374
|
+
)
|
|
375
|
+
if os.path.exists(shell_def_path):
|
|
376
|
+
with open(shell_def_path, encoding="utf8") as stream:
|
|
377
|
+
match = re.search(
|
|
378
|
+
r"cloudshell_standard:\s*cloudshell_(?P<name>\S+)_standard_(?P<version>\S+)\.\w+$", # noqa: E501
|
|
379
|
+
stream.read(),
|
|
380
|
+
re.MULTILINE,
|
|
381
|
+
)
|
|
382
|
+
if match:
|
|
383
|
+
name = str(match.groupdict()["name"]).replace("_", "-")
|
|
384
|
+
version = str(match.groupdict()["version"].replace("_", "."))
|
|
385
|
+
|
|
386
|
+
if name not in standards or version not in standards[name]:
|
|
387
|
+
raise click.ClickException(
|
|
388
|
+
"Shell template and available standards are not compatible"
|
|
389
|
+
)
|
|
390
|
+
else:
|
|
391
|
+
raise click.ClickException(
|
|
392
|
+
"Can not determine standard version for provided template"
|
|
393
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from shellfoundry.exceptions import ShellYmlMissingException, WrongShellYmlException
|
|
9
|
+
from shellfoundry.utilities.package_builder import PackageBuilder
|
|
10
|
+
from shellfoundry.utilities.shell_config_reader import ShellConfigReader
|
|
11
|
+
from shellfoundry.utilities.shell_package import ShellPackage
|
|
12
|
+
from shellfoundry.utilities.shell_package_builder import ShellPackageBuilder
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PackCommandExecutor(object):
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.config_reader = ShellConfigReader()
|
|
18
|
+
self.package_builder = PackageBuilder()
|
|
19
|
+
self.shell_package_builder = ShellPackageBuilder()
|
|
20
|
+
|
|
21
|
+
def pack(self):
|
|
22
|
+
|
|
23
|
+
current_path = os.getcwd()
|
|
24
|
+
|
|
25
|
+
shell_package = ShellPackage(current_path)
|
|
26
|
+
if shell_package.is_layer_one():
|
|
27
|
+
click.secho(
|
|
28
|
+
"Packaging a L1 shell directly via shellfoundry is not supported.",
|
|
29
|
+
fg="yellow",
|
|
30
|
+
)
|
|
31
|
+
elif shell_package.is_tosca():
|
|
32
|
+
self.shell_package_builder.pack(current_path)
|
|
33
|
+
else:
|
|
34
|
+
self._pack_old_school_shell(current_path)
|
|
35
|
+
|
|
36
|
+
def _pack_old_school_shell(self, current_path):
|
|
37
|
+
try:
|
|
38
|
+
config = self.config_reader.read()
|
|
39
|
+
self.package_builder.build_package(
|
|
40
|
+
current_path, config.name, config.driver_name
|
|
41
|
+
)
|
|
42
|
+
except ShellYmlMissingException:
|
|
43
|
+
click.echo("shell.yml file is missing")
|
|
44
|
+
except WrongShellYmlException:
|
|
45
|
+
click.echo("shell.yml format is wrong")
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
import click
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
import shellfoundry.exceptions as exc
|
|
7
|
+
from shellfoundry import MASTER_BRANCH_NAME
|
|
8
|
+
from shellfoundry.utilities import GEN_TWO_FILTER
|
|
9
|
+
from shellfoundry.utilities.template_retriever import (
|
|
10
|
+
FilteredTemplateRetriever,
|
|
11
|
+
TemplateRetriever,
|
|
12
|
+
)
|
|
13
|
+
from shellfoundry.utilities.template_versions import TemplateVersions
|
|
14
|
+
|
|
15
|
+
LATEST_STAMP = "{} (latest)"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ShowCommandExecutor(object):
|
|
19
|
+
def __init__(self, template_retriever=None):
|
|
20
|
+
self.template_retriever = template_retriever or FilteredTemplateRetriever(
|
|
21
|
+
GEN_TWO_FILTER, TemplateRetriever()
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def show(self, template_name):
|
|
25
|
+
try:
|
|
26
|
+
template_repo = self.template_retriever.get_templates()[template_name][
|
|
27
|
+
0
|
|
28
|
+
].repository
|
|
29
|
+
except Exception:
|
|
30
|
+
raise click.ClickException(
|
|
31
|
+
"The template '{}' does not exist, please specify a valid 2nd Gen shell template.".format( # noqa: E501
|
|
32
|
+
template_name
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if not template_repo:
|
|
37
|
+
raise click.ClickException("Repository url is empty")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
branches = TemplateVersions(
|
|
41
|
+
*template_repo.split("/")[-2:]
|
|
42
|
+
).get_versions_of_template()
|
|
43
|
+
except (requests.RequestException, exc.NoVersionsHaveBeenFoundException) as ex:
|
|
44
|
+
raise click.ClickException(str(ex))
|
|
45
|
+
branches.remove(MASTER_BRANCH_NAME)
|
|
46
|
+
if not TemplateVersions.has_versions(
|
|
47
|
+
branches
|
|
48
|
+
): # validating that besides master there are other versions
|
|
49
|
+
raise click.ClickException("No versions have been found for this template")
|
|
50
|
+
self.mark_latest(branches)
|
|
51
|
+
for branch_name in branches:
|
|
52
|
+
click.echo(branch_name)
|
|
53
|
+
|
|
54
|
+
def mark_latest(self, branches):
|
|
55
|
+
branches[0] = LATEST_STAMP.format(branches[0])
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"StandardName": "cloudshell_compute_standard",
|
|
4
|
+
"Versions": [
|
|
5
|
+
"2.0.0"
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"StandardName": "cloudshell_deployed_app_standard",
|
|
10
|
+
"Versions": [
|
|
11
|
+
"1.0.0"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"StandardName": "cloudshell_firewall_standard",
|
|
16
|
+
"Versions": [
|
|
17
|
+
"3.0.0"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"StandardName": "cloudshell_networking_standard",
|
|
22
|
+
"Versions": [
|
|
23
|
+
"5.0.0"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"StandardName": "cloudshell_on_prem_app_standard",
|
|
28
|
+
"Versions": [
|
|
29
|
+
"1.0.0"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"StandardName": "cloudshell_pdu_standard",
|
|
34
|
+
"Versions": [
|
|
35
|
+
"2.0.0"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"StandardName": "cloudshell_resource_standard",
|
|
40
|
+
"Versions": [
|
|
41
|
+
"2.0.0"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
templates:
|
|
2
|
+
- name : gen1/resource
|
|
3
|
+
description : 1st generation shell template for basic inventory resources
|
|
4
|
+
repository : https://github.com/QualiSystems/shell-resource-standard
|
|
5
|
+
params:
|
|
6
|
+
project_name :
|
|
7
|
+
min_cs_ver: 7.0
|
|
8
|
+
- name: gen1/resource-clean
|
|
9
|
+
params:
|
|
10
|
+
project_name :
|
|
11
|
+
description : 1st generation shell template for basic inventory resources (without sample commands)
|
|
12
|
+
repository : https://github.com/QualiSystems/resource-shell-standard-clean
|
|
13
|
+
min_cs_ver: 7.0
|
|
14
|
+
- name: gen1/deployed-app
|
|
15
|
+
params:
|
|
16
|
+
project_name :
|
|
17
|
+
description : 1st generation shell template for a deployed app
|
|
18
|
+
repository : https://github.com/QualiSystems/shell-deployedapp-standard
|
|
19
|
+
min_cs_ver: 7.0
|
|
20
|
+
- name: gen1/networking/switch
|
|
21
|
+
description : 1st generation shell template for a standard switch
|
|
22
|
+
repository : https://github.com/QualiSystems/shell-networking-standard
|
|
23
|
+
params:
|
|
24
|
+
project_name :
|
|
25
|
+
family_name : Switch
|
|
26
|
+
min_cs_ver: 7.0
|
|
27
|
+
- name: gen1/networking/router
|
|
28
|
+
description : 1st generation shell template for a standard router
|
|
29
|
+
repository : https://github.com/QualiSystems/shell-networking-standard
|
|
30
|
+
params:
|
|
31
|
+
project_name :
|
|
32
|
+
family_name : Router
|
|
33
|
+
min_cs_ver: 7.0
|
|
34
|
+
- name: gen1/pdu
|
|
35
|
+
description : 1st generation shell template for a standard pdu
|
|
36
|
+
repository : https://github.com/QualiSystems/shell-pdu-standard
|
|
37
|
+
params:
|
|
38
|
+
project_name :
|
|
39
|
+
family_name : PDU
|
|
40
|
+
min_cs_ver: 7.0
|
|
41
|
+
- name: gen1/firewall
|
|
42
|
+
description : 1st generation shell template for a standard firewall
|
|
43
|
+
repository : https://github.com/QualiSystems/shell-firewall-standard
|
|
44
|
+
params:
|
|
45
|
+
project_name :
|
|
46
|
+
family_name : Firewall
|
|
47
|
+
min_cs_ver: 7.0
|
|
48
|
+
- name: gen1/compute
|
|
49
|
+
description : 1st generation shell template for compute servers
|
|
50
|
+
repository : https://github.com/QualiSystems/shell-compute-standard
|
|
51
|
+
params:
|
|
52
|
+
project_name :
|
|
53
|
+
family_name :
|
|
54
|
+
min_cs_ver: 7.0
|
|
55
|
+
- name: layer-1-switch
|
|
56
|
+
description : A native shell template for layer 1 switches
|
|
57
|
+
repository : https://github.com/QualiSystems/shell-L1-standard
|
|
58
|
+
params:
|
|
59
|
+
project_name :
|
|
60
|
+
family_name :
|
|
61
|
+
min_cs_ver: 7.0
|
|
62
|
+
- name : gen2/networking/switch
|
|
63
|
+
params:
|
|
64
|
+
project_name :
|
|
65
|
+
family_name: Switch
|
|
66
|
+
description : 2nd generation shell template for a standard switch
|
|
67
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-networking-template
|
|
68
|
+
min_cs_ver: 8.0
|
|
69
|
+
- name : gen2/networking/router
|
|
70
|
+
params:
|
|
71
|
+
project_name :
|
|
72
|
+
family_name: Router
|
|
73
|
+
description : 2nd generation shell template for a standard router
|
|
74
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-networking-template
|
|
75
|
+
min_cs_ver: 8.0
|
|
76
|
+
- name : gen2/networking/wireless-controller
|
|
77
|
+
params:
|
|
78
|
+
project_name :
|
|
79
|
+
family_name: WirelessController
|
|
80
|
+
description : 2nd generation shell template for a standard wireless controller
|
|
81
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-networking-template
|
|
82
|
+
min_cs_ver: 8.0
|
|
83
|
+
- name : gen2/compute
|
|
84
|
+
params:
|
|
85
|
+
project_name :
|
|
86
|
+
family_name :
|
|
87
|
+
description : 2nd generation shell template for compute servers
|
|
88
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-compute-template
|
|
89
|
+
min_cs_ver: 8.0
|
|
90
|
+
- name : gen2/deployed-app
|
|
91
|
+
params:
|
|
92
|
+
project_name :
|
|
93
|
+
family_name :
|
|
94
|
+
description : 2nd generation shell template for a deployed app
|
|
95
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-deployedapp-template
|
|
96
|
+
min_cs_ver: 8.0
|
|
97
|
+
- name : gen2/pdu
|
|
98
|
+
params:
|
|
99
|
+
project_name :
|
|
100
|
+
family_name :
|
|
101
|
+
description : 2nd generation shell template for a standard pdu
|
|
102
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-pdu-template
|
|
103
|
+
min_cs_ver: 8.0
|
|
104
|
+
- name : gen2/resource
|
|
105
|
+
params:
|
|
106
|
+
project_name :
|
|
107
|
+
family_name :
|
|
108
|
+
description : 2nd generation shell template for basic inventory resources
|
|
109
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-resource-template
|
|
110
|
+
min_cs_ver: 8.0
|
|
111
|
+
- name : gen2/firewall
|
|
112
|
+
params:
|
|
113
|
+
project_name :
|
|
114
|
+
family_name :
|
|
115
|
+
description : 2nd generation shell template for firewall resources
|
|
116
|
+
repository : https://github.com/QualiSystems/shellfoundry-tosca-firewall-template
|
|
117
|
+
min_cs_ver: 8.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .version_check import shellfoundry_version_check # noqa: F401
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from shellfoundry.utilities.standards.consts import STANDARD_NAME_KEY, VERSIONS_KEY
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def standard_transformation(fetch):
|
|
8
|
+
def wrapper(self, **kwargs):
|
|
9
|
+
result = fetch(self, **kwargs)
|
|
10
|
+
return {
|
|
11
|
+
i[STANDARD_NAME_KEY]
|
|
12
|
+
.lower()
|
|
13
|
+
.lstrip("cloudshell")
|
|
14
|
+
.rstrip("standard")
|
|
15
|
+
.strip("_")
|
|
16
|
+
.replace("_", "-"): i[VERSIONS_KEY]
|
|
17
|
+
for i in result
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return wrapper
|