devstack-cli 11.0.84__tar.gz → 11.0.85__tar.gz
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.
- {devstack_cli-11.0.84/src/devstack_cli.egg-info → devstack_cli-11.0.85}/PKG-INFO +1 -1
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/pyproject.toml +1 -1
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/cli.py +64 -10
- {devstack_cli-11.0.84 → devstack_cli-11.0.85/src/devstack_cli.egg-info}/PKG-INFO +1 -1
- devstack_cli-11.0.85/src/version.py +9 -0
- devstack_cli-11.0.84/src/version.py +0 -9
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/LICENSE +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/README.md +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/setup.cfg +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/__init__.py +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/devstack_cli.egg-info/SOURCES.txt +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/devstack_cli.egg-info/dependency_links.txt +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/devstack_cli.egg-info/entry_points.txt +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/devstack_cli.egg-info/requires.txt +0 -0
- {devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/devstack_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: devstack-cli
|
3
|
-
Version: 11.0.
|
3
|
+
Version: 11.0.85
|
4
4
|
Summary: Command-line access to Cloud Development Environments (CDEs) created by Cloudomation DevStack
|
5
5
|
Author-email: Stefan Mückstein <stefan@cloudomation.com>
|
6
6
|
Project-URL: Homepage, https://cloudomation.com/
|
@@ -10,6 +10,7 @@ import json
|
|
10
10
|
import logging
|
11
11
|
import os
|
12
12
|
import pathlib
|
13
|
+
import re
|
13
14
|
import readline
|
14
15
|
import shlex
|
15
16
|
import shutil
|
@@ -1222,6 +1223,12 @@ class Cli:
|
|
1222
1223
|
self.port_forwarding_task = None
|
1223
1224
|
|
1224
1225
|
async def _bg_port_forwarding(self: 'Cli') -> None:
|
1226
|
+
remote_username = self.cde_type['value']['remote-username']
|
1227
|
+
if re.match(r'[^a-zA-Z0-9]', remote_username):
|
1228
|
+
raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
|
1229
|
+
hostname = self.hostname
|
1230
|
+
if re.match(r'[^a-zA-Z0-9]', hostname):
|
1231
|
+
raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
|
1225
1232
|
service_ports = self.cde_type['value'].get('service-ports')
|
1226
1233
|
if service_ports is None:
|
1227
1234
|
service_ports = [
|
@@ -1238,6 +1245,11 @@ class Cli:
|
|
1238
1245
|
for port
|
1239
1246
|
in service_ports
|
1240
1247
|
]
|
1248
|
+
for port in service_ports:
|
1249
|
+
if port[0] < 1 or port[0] > 65535:
|
1250
|
+
raise Exception(f'Invalid port: "{port[0]}". Only numbers between 1 and 65535 are allowed.')
|
1251
|
+
if port[1] < 1 or port[1] > 65535:
|
1252
|
+
raise Exception(f'Invalid port: "{port[1]}". Only numbers between 1 and 65535 are allowed.')
|
1241
1253
|
while True:
|
1242
1254
|
logger.info('Starting port forwarding of %s', ', '.join(str(port[0]) for port in service_ports))
|
1243
1255
|
try:
|
@@ -1247,7 +1259,7 @@ class Cli:
|
|
1247
1259
|
'-o', 'ConnectTimeout=10',
|
1248
1260
|
'-o', f'UserKnownHostsFile={self.known_hosts_file.name}',
|
1249
1261
|
'-NT',
|
1250
|
-
f
|
1262
|
+
f'{remote_username}@{hostname}',
|
1251
1263
|
*itertools.chain.from_iterable([
|
1252
1264
|
('-L', f'{port[0]}:localhost:{port[1]}')
|
1253
1265
|
for port
|
@@ -1427,13 +1439,22 @@ class Cli:
|
|
1427
1439
|
return await self._process_remote_item_copy_file(file_info.filename)
|
1428
1440
|
|
1429
1441
|
async def _process_remote_item_copy_dir(self: 'Cli', filename: str) -> str:
|
1442
|
+
remote_username = self.cde_type['value']['remote-username']
|
1443
|
+
if re.match(r'[^a-zA-Z0-9]', remote_username):
|
1444
|
+
raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
|
1445
|
+
hostname = self.hostname
|
1446
|
+
if re.match(r'[^a-zA-Z0-9]', hostname):
|
1447
|
+
raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
|
1448
|
+
remote_source_directory = self.cde_type['value']['remote-source-directory']
|
1449
|
+
if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
|
1450
|
+
raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
|
1430
1451
|
await run_subprocess(
|
1431
1452
|
'rsync',
|
1432
1453
|
[
|
1433
1454
|
'-e', f'ssh -o ConnectTimeout=10 -o UserKnownHostsFile={self.known_hosts_file.name}',
|
1434
1455
|
'--archive',
|
1435
1456
|
'--checksum',
|
1436
|
-
f
|
1457
|
+
f'{remote_username}@{hostname}:{remote_source_directory}/{filename}/',
|
1437
1458
|
str(self.local_source_directory / filename),
|
1438
1459
|
],
|
1439
1460
|
name='Copy remote directory',
|
@@ -1441,23 +1462,35 @@ class Cli:
|
|
1441
1462
|
return f'Copied directory "{filename}"'
|
1442
1463
|
|
1443
1464
|
async def _process_remote_item_copy_file(self: 'Cli', filename: str) -> str:
|
1465
|
+
remote_source_directory = self.cde_type['value']['remote-source-directory']
|
1466
|
+
if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
|
1467
|
+
raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
|
1444
1468
|
await self.loop.run_in_executor(
|
1445
1469
|
executor=None,
|
1446
1470
|
func=functools.partial(
|
1447
1471
|
self.sftp_client.get,
|
1448
|
-
remotepath=f
|
1472
|
+
remotepath=f'{remote_source_directory}/{filename}',
|
1449
1473
|
localpath=str(self.local_source_directory / filename),
|
1450
1474
|
),
|
1451
1475
|
)
|
1452
1476
|
return f'Copied file "{filename}"'
|
1453
1477
|
|
1454
1478
|
async def _process_remote_item_clone(self: 'Cli', filename: str) -> str:
|
1479
|
+
remote_username = self.cde_type['value']['remote-username']
|
1480
|
+
if re.match(r'[^a-zA-Z0-9]', remote_username):
|
1481
|
+
raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
|
1482
|
+
hostname = self.hostname
|
1483
|
+
if re.match(r'[^a-zA-Z0-9]', hostname):
|
1484
|
+
raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
|
1485
|
+
remote_source_directory = self.cde_type['value']['remote-source-directory']
|
1486
|
+
if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
|
1487
|
+
raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
|
1455
1488
|
await run_subprocess(
|
1456
1489
|
'git',
|
1457
1490
|
[
|
1458
1491
|
'clone',
|
1459
1492
|
'-q',
|
1460
|
-
f
|
1493
|
+
f'{remote_username}@{hostname}:{remote_source_directory}/{filename}',
|
1461
1494
|
],
|
1462
1495
|
name='Git clone',
|
1463
1496
|
cwd=self.local_source_directory,
|
@@ -1472,7 +1505,7 @@ class Cli:
|
|
1472
1505
|
shlex.join([
|
1473
1506
|
'git',
|
1474
1507
|
'-C',
|
1475
|
-
f
|
1508
|
+
f'{remote_source_directory}/{filename}',
|
1476
1509
|
'config',
|
1477
1510
|
'--get',
|
1478
1511
|
'remote.origin.url',
|
@@ -1497,10 +1530,19 @@ class Cli:
|
|
1497
1530
|
return f'Cloned repository "{filename}"'
|
1498
1531
|
|
1499
1532
|
async def _background_sync(self: 'Cli') -> None:
|
1533
|
+
remote_username = self.cde_type['value']['remote-username']
|
1534
|
+
if re.match(r'[^a-zA-Z0-9]', remote_username):
|
1535
|
+
raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
|
1536
|
+
hostname = self.hostname
|
1537
|
+
if re.match(r'[^a-zA-Z0-9]', hostname):
|
1538
|
+
raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
|
1539
|
+
remote_source_directory = self.cde_type['value']['remote-source-directory']
|
1540
|
+
if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
|
1541
|
+
raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
|
1500
1542
|
logger.debug('Starting background sync')
|
1501
1543
|
self.local_source_directory.mkdir(parents=True, exist_ok=True)
|
1502
1544
|
with contextlib.suppress(OSError):
|
1503
|
-
self.sftp_client.mkdir(
|
1545
|
+
self.sftp_client.mkdir(remote_source_directory)
|
1504
1546
|
file_sync_exclusions = self.cde_type['value'].get('file-sync-exclusions')
|
1505
1547
|
if file_sync_exclusions is None:
|
1506
1548
|
file_sync_exclusions = [
|
@@ -1548,7 +1590,7 @@ class Cli:
|
|
1548
1590
|
'--human-readable',
|
1549
1591
|
'--verbose',
|
1550
1592
|
f'{self.local_source_directory}/',
|
1551
|
-
f
|
1593
|
+
f'{remote_username}@{hostname}:{remote_source_directory}',
|
1552
1594
|
],
|
1553
1595
|
name='Background sync',
|
1554
1596
|
print_to_debug_log=True,
|
@@ -1564,19 +1606,31 @@ class Cli:
|
|
1564
1606
|
logger.info('Background sync done')
|
1565
1607
|
|
1566
1608
|
async def _reverse_background_sync(self: 'Cli') -> None:
|
1609
|
+
remote_username = self.cde_type['value']['remote-username']
|
1610
|
+
if re.match(r'[^a-zA-Z0-9]', remote_username):
|
1611
|
+
raise Exception(f'Invalid remote username: "{remote_username}". Only alphanumeric characters are allowed.')
|
1612
|
+
hostname = self.hostname
|
1613
|
+
if re.match(r'[^a-zA-Z0-9]', hostname):
|
1614
|
+
raise Exception(f'Invalid hostname: "{hostname}". Only alphanumeric characters are allowed.')
|
1615
|
+
remote_source_directory = self.cde_type['value']['remote-source-directory']
|
1616
|
+
if re.match(r'[^a-zA-Z0-9/_.-]', remote_source_directory):
|
1617
|
+
raise Exception(f'Invalid remote source directory: "{remote_source_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
|
1567
1618
|
logger.debug('Starting reverse background sync')
|
1619
|
+
remote_output_directory = self.cde_type['value']['remote-output-directory']
|
1620
|
+
if re.match(r'[^a-zA-Z0-9/_.-]', remote_output_directory):
|
1621
|
+
raise Exception(f'Invalid remote output directory: "{remote_output_directory}". Only alphanumeric characters, slashes, underscores, dots and hyphens are allowed.')
|
1568
1622
|
with contextlib.suppress(OSError):
|
1569
|
-
self.sftp_client.mkdir(
|
1623
|
+
self.sftp_client.mkdir(remote_output_directory)
|
1570
1624
|
self.local_output_directory.mkdir(parents=True, exist_ok=True)
|
1571
1625
|
try:
|
1572
|
-
|
1626
|
+
await run_subprocess(
|
1573
1627
|
'rsync',
|
1574
1628
|
[
|
1575
1629
|
'-e', f'ssh -o ConnectTimeout=10 -o UserKnownHostsFile={self.known_hosts_file.name}',
|
1576
1630
|
'--archive',
|
1577
1631
|
'--exclude', '__pycache__',
|
1578
1632
|
'--human-readable',
|
1579
|
-
f
|
1633
|
+
f'{remote_username}@{hostname}:{remote_output_directory}/',
|
1580
1634
|
str(self.local_output_directory),
|
1581
1635
|
],
|
1582
1636
|
name='Reverse background sync',
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: devstack-cli
|
3
|
-
Version: 11.0.
|
3
|
+
Version: 11.0.85
|
4
4
|
Summary: Command-line access to Cloud Development Environments (CDEs) created by Cloudomation DevStack
|
5
5
|
Author-email: Stefan Mückstein <stefan@cloudomation.com>
|
6
6
|
Project-URL: Homepage, https://cloudomation.com/
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{devstack_cli-11.0.84 → devstack_cli-11.0.85}/src/devstack_cli.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|