primitive 0.1.62__py3-none-any.whl → 0.1.63__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.
primitive/__about__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2024-present Dylan Stein <dylan@primitive.tech>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- __version__ = "0.1.62"
4
+ __version__ = "0.1.63"
@@ -20,7 +20,7 @@ class Agent(BaseAction):
20
20
  logger.info(" [*] primitive")
21
21
  logger.info(f" [*] Version: {__version__}")
22
22
 
23
- # Create cache dir if it doesnt exist
23
+ # Create cache dir if it doesn't exist
24
24
  cache_dir = get_sources_cache()
25
25
 
26
26
  # Create uploader
@@ -53,6 +53,11 @@ class Agent(BaseAction):
53
53
  logger.debug("Active Reservation:")
54
54
  logger.debug(f"Node ID: {active_reservation_id}")
55
55
  logger.debug(f"PK: {active_reservation_pk}")
56
+
57
+ logger.debug("Running pre provisioning steps for reservation.")
58
+ self.primitive.provisioning.add_reservation_authorized_keys(
59
+ reservation_id=active_reservation_id
60
+ )
56
61
  else:
57
62
  if (
58
63
  hardware["activeReservation"] is None
@@ -62,6 +67,12 @@ class Agent(BaseAction):
62
67
  logger.debug("Previous Reservation is Complete:")
63
68
  logger.debug(f"Node ID: {active_reservation_id}")
64
69
  logger.debug(f"PK: {active_reservation_pk}")
70
+ logger.debug(
71
+ "Running cleanup provisioning steps for reservation."
72
+ )
73
+ self.primitive.provisioning.remove_reservation_authorized_keys(
74
+ reservation_id=active_reservation_id
75
+ )
65
76
  active_reservation_id = None
66
77
  active_reservation_pk = None
67
78
 
primitive/client.py CHANGED
@@ -1,20 +1,22 @@
1
1
  import sys
2
+
3
+ from loguru import logger
4
+
5
+ from .agent.actions import Agent
2
6
  from .auth.actions import Auth
3
- from .projects.actions import Projects
4
- from .utils.config import read_config_file
7
+ from .daemons.actions import Daemons
8
+ from .exec.actions import Exec
5
9
  from .files.actions import Files
6
- from .sim.actions import Sim
7
- from .hardware.actions import Hardware
8
- from .lint.actions import Lint
9
- from .agent.actions import Agent
10
10
  from .git.actions import Git
11
- from .daemons.actions import Daemons
11
+ from .hardware.actions import Hardware
12
12
  from .jobs.actions import Jobs
13
+ from .lint.actions import Lint
13
14
  from .organizations.actions import Organizations
14
- from .exec.actions import Exec
15
+ from .projects.actions import Projects
16
+ from .provisioning.actions import Provisioning
15
17
  from .reservations.actions import Reservations
16
-
17
- from loguru import logger
18
+ from .sim.actions import Sim
19
+ from .utils.config import read_config_file
18
20
 
19
21
  logger.disable("primitive")
20
22
 
@@ -67,6 +69,7 @@ class Primitive:
67
69
  self.git: Git = Git(self)
68
70
  self.daemons: Daemons = Daemons(self)
69
71
  self.exec: Exec = Exec(self)
72
+ self.provisioning: Provisioning = Provisioning(self)
70
73
 
71
74
  def get_host_config(self):
72
75
  self.full_config = read_config_file()
primitive/exec/actions.py CHANGED
@@ -1,4 +1,3 @@
1
- import tempfile
2
1
  import typing
3
2
 
4
3
  from primitive.exec.interactive import interactive_shell
@@ -46,34 +45,16 @@ class Exec(BaseAction):
46
45
  reservation_id=reservation["id"], desired_status="in_progress"
47
46
  )
48
47
 
49
- ssh_credentials = self.primitive.hardware.get_hardware_ssh_credentials(
50
- hardware_id=hardware["id"]
51
- )
52
-
53
- ssh_hostname = ssh_credentials["ssh_hostname"]
54
- ssh_username = ssh_credentials["ssh_username"]
55
- ssh_password = ssh_credentials["ssh_password"]
56
- ssh_private_key = ssh_credentials["ssh_private_key"]
48
+ ssh_hostname = hardware["hostname"]
49
+ ssh_username = hardware["ssh_username"]
57
50
 
58
51
  ssh_client = SSHClient()
59
52
  ssh_client.load_system_host_keys()
60
- keyfile = None
61
- if ssh_private_key:
62
- keyfile = tempfile.NamedTemporaryFile()
63
- keyfile.write(ssh_private_key.encode())
64
- keyfile.flush()
65
- ssh_client.connect(
66
- hostname=ssh_hostname,
67
- username=ssh_username,
68
- key_filename=keyfile.name,
69
- )
70
- else:
71
- ssh_client.connect(
72
- hostname=ssh_hostname,
73
- username=ssh_username,
74
- pkey=ssh_private_key,
75
- password=ssh_password,
76
- )
53
+
54
+ ssh_client.connect(
55
+ hostname=ssh_hostname,
56
+ username=ssh_username,
57
+ )
77
58
 
78
59
  if command:
79
60
  formatted_command = " ".join(command)
@@ -86,8 +67,6 @@ class Exec(BaseAction):
86
67
  channel.invoke_shell()
87
68
  interactive_shell(channel)
88
69
  ssh_client.close()
89
- if keyfile:
90
- keyfile.close()
91
70
 
92
71
  if created_reservation_on_behalf_of_user:
93
72
  print("Cleaning up reservation.")
@@ -22,7 +22,7 @@ from .graphql.mutations import (
22
22
  hardware_update_mutation,
23
23
  register_hardware_mutation,
24
24
  )
25
- from .graphql.queries import hardware_list, hardware_ssh_credentials
25
+ from .graphql.queries import hardware_list
26
26
 
27
27
  if typing.TYPE_CHECKING:
28
28
  pass
@@ -303,7 +303,7 @@ class Hardware(BaseAction):
303
303
  # and headers are set correctly
304
304
  self.primitive.get_host_config()
305
305
  self.check_in_http(is_healthy=True)
306
- return True
306
+ return result
307
307
 
308
308
  @guard
309
309
  def update_hardware_system_info(self):
@@ -479,16 +479,3 @@ class Hardware(BaseAction):
479
479
  raise Exception(f"No hardware found with slug {hardware_identifier}")
480
480
 
481
481
  return hardware
482
-
483
- @guard
484
- def get_hardware_ssh_credentials(self, hardware_id: str):
485
- query = gql(hardware_ssh_credentials)
486
-
487
- variables = {
488
- "id": hardware_id,
489
- }
490
- result = self.primitive.session.execute(
491
- query, variable_values=variables, get_execution_result=True
492
- )
493
- ssh_credentials = result.data.get("hardware").get("sshCredentials")
494
- return ssh_credentials
@@ -10,6 +10,8 @@ fragment HardwareFragment on Hardware {
10
10
  isOnline
11
11
  isQuarantined
12
12
  isHealthy
13
+ hostname
14
+ sshUsername
13
15
  capabilities {
14
16
  id
15
17
  pk
@@ -29,13 +29,3 @@ query hardwareList(
29
29
  }
30
30
  """
31
31
  )
32
-
33
- hardware_ssh_credentials = """
34
- query hardwareSSHCredentials($id: GlobalID!) {
35
- hardware(id: $id) {
36
- id
37
- pk
38
- sshCredentials
39
- }
40
- }
41
- """
File without changes
@@ -0,0 +1,62 @@
1
+ from pathlib import Path
2
+
3
+ from gql import gql
4
+
5
+ from primitive.utils.actions import BaseAction
6
+
7
+ from ..utils.auth import guard
8
+ from .graphql.queries import authorized_keys_query
9
+
10
+ HOME_DIRECTORY = Path.home()
11
+ AUTHORIZED_KEYS_FILEPATH = Path(HOME_DIRECTORY / ".ssh" / "authorized_keys")
12
+
13
+
14
+ class Provisioning(BaseAction):
15
+ @guard
16
+ def get_authorized_keys(self, reservation_id: str) -> str:
17
+ variables = {
18
+ "reservationId": reservation_id,
19
+ }
20
+ query = gql(authorized_keys_query)
21
+ result = self.primitive.session.execute(
22
+ query, variable_values=variables, get_execution_result=True
23
+ )
24
+ return result.data["authorizedKeys"]
25
+
26
+ def add_reservation_authorized_keys(self, reservation_id: str) -> None:
27
+ AUTHORIZED_KEYS_BACKUP_FILEPATH = Path(
28
+ HOME_DIRECTORY / ".ssh" / f"authorized_keys.bak-{reservation_id}"
29
+ )
30
+
31
+ if AUTHORIZED_KEYS_FILEPATH.exists():
32
+ AUTHORIZED_KEYS_BACKUP_FILEPATH.write_text(
33
+ AUTHORIZED_KEYS_FILEPATH.read_text()
34
+ )
35
+ else:
36
+ AUTHORIZED_KEYS_FILEPATH.touch()
37
+
38
+ authorized_keys = self.get_authorized_keys(reservation_id=reservation_id)
39
+
40
+ AUTHORIZED_KEYS_FILEPATH.write_text(
41
+ AUTHORIZED_KEYS_FILEPATH.read_text()
42
+ + f"\n## START PRIMITIVE SSH PUBLIC KEYS FOR RESERVATION ID {reservation_id}\n"
43
+ + authorized_keys
44
+ + f"\n## END PRIMITIVE SSH PUBLIC KEYS FOR RESERVATION ID {reservation_id}\n"
45
+ )
46
+
47
+ # self.primitive.sshd.reload()
48
+
49
+ def remove_reservation_authorized_keys(self, reservation_id: str) -> None:
50
+ AUTHORIZED_KEYS_BACKUP_FILEPATH = Path(
51
+ HOME_DIRECTORY / ".ssh" / f"authorized_keys.bak-{reservation_id}"
52
+ )
53
+
54
+ if AUTHORIZED_KEYS_BACKUP_FILEPATH.exists():
55
+ AUTHORIZED_KEYS_FILEPATH.write_text(
56
+ AUTHORIZED_KEYS_BACKUP_FILEPATH.read_text()
57
+ )
58
+ AUTHORIZED_KEYS_BACKUP_FILEPATH.unlink()
59
+ else:
60
+ AUTHORIZED_KEYS_FILEPATH.unlink()
61
+
62
+ # self.primitive.sshd.reload()
File without changes
@@ -0,0 +1,5 @@
1
+ authorized_keys_query = """
2
+ query authorizedKeys($reservationId: GlobalID!) {
3
+ authorizedKeys(reservationId: $reservationId)
4
+ }
5
+ """
@@ -32,7 +32,7 @@ fragment ReservationFragment on Reservation {
32
32
  reason
33
33
  startedAt
34
34
  endedAt
35
- elapsedTime
35
+ # elapsedTime
36
36
  status
37
37
  conclusion
38
38
  conclusionMessage
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: primitive
3
- Version: 0.1.62
3
+ Version: 0.1.63
4
4
  Project-URL: Documentation, https://github.com//primitivecorp/primitive-cli#readme
5
5
  Project-URL: Issues, https://github.com//primitivecorp/primitive-cli/issues
6
6
  Project-URL: Source, https://github.com//primitivecorp/primitive-cli
7
7
  Author-email: Dylan Stein <dylan@primitive.tech>, Chase Zimmerman <chase@primitive.tech>
8
- License-Expression: MIT
9
- License-File: LICENSE.txt
8
+ License: MIT
10
9
  Classifier: Development Status :: 4 - Beta
11
10
  Classifier: Programming Language :: Python
12
11
  Classifier: Programming Language :: Python :: 3
@@ -1,9 +1,9 @@
1
- primitive/__about__.py,sha256=geKDLLFDQydMN_sAK9SDHgrotZtzInxl2yNgIL4tHng,130
1
+ primitive/__about__.py,sha256=uiVaG3uarbeydunpM548F3cr2wnnZhtxTkRYjlZVUoU,130
2
2
  primitive/__init__.py,sha256=bwKdgggKNVssJFVPfKSxqFMz4IxSr54WWbmiZqTMPNI,106
3
3
  primitive/cli.py,sha256=CGmWiqqCLMHtHGOUPuf3tVO6VvChBZ1VdSwCCglnBgA,2582
4
- primitive/client.py,sha256=p-5z1iGM8ZydIrkYf4R6b7Yna73oszlGdXim9-Zsbyk,2364
4
+ primitive/client.py,sha256=P7cCDperMu3pxlmRAP-H2owM-cj1kRlZWrqujxnWa4o,2473
5
5
  primitive/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- primitive/agent/actions.py,sha256=B7d2oNMjtjUP2RhD-QnNDWNl3jHwjUDk5KLWQ2OnNQ4,5883
6
+ primitive/agent/actions.py,sha256=Hosy2o2FntfBtcNqqHuMFq9dm99EVfySy0v2JGeufvc,6474
7
7
  primitive/agent/commands.py,sha256=-dVDilELfkGfbZB7qfEPs77Dm1oT62qJj4tsIk4KoxI,254
8
8
  primitive/agent/process.py,sha256=LVI-RB4a0YEuXUTYMXKL5Xi9euNwUI2nxj00mv8EFOg,2253
9
9
  primitive/agent/provision.py,sha256=rmwnro1K5F8mwtd45XAq7RVQmpDWnbBCQ8X_qgWhm3M,1546
@@ -20,7 +20,7 @@ primitive/daemons/commands.py,sha256=-Muh-6ib4uAVtPn_67AcMrDwuCwYlCnRQozCi2Xurmk
20
20
  primitive/daemons/launch_agents.py,sha256=qovt32gwpjGDd82z_SY5EGCUjaUyNA49pZFajZsw3eE,4796
21
21
  primitive/daemons/launch_service.py,sha256=FPB9qKEjhllRfEpct0ng2L9lpIaGJbQwn1JdFT8uBA8,5600
22
22
  primitive/exec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- primitive/exec/actions.py,sha256=Q7Nj4SVIh2XH83mirpBRQietwWZDZXdoBF3gGvUVzCU,3425
23
+ primitive/exec/actions.py,sha256=hgUYi_G69SPbMRpVZv8EjeqIy41apXZIIw9lcg37zAY,2633
24
24
  primitive/exec/commands.py,sha256=66LO2kkJC-ynNZQpUCXv4Ol15QoacdSZAHblePDcmLo,510
25
25
  primitive/exec/interactive.py,sha256=TscY6s2ZysijidKPheq6y-fCErUVLS0zcdTW8XyFWGI,2435
26
26
  primitive/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -38,12 +38,12 @@ primitive/graphql/relay.py,sha256=bmij2AjdpURQ6GGVCxwWhauF-r_SxuAU2oJ4sDbLxpI,72
38
38
  primitive/graphql/sdk.py,sha256=BhCGmDtc4sNnH8CxbQSJyFwOZ-ZSqMtjsxMB3JRBhPw,1456
39
39
  primitive/graphql/utility_fragments.py,sha256=uIjwILC4QtWNyO5vu77VjQf_p0jvP3A9q_6zRq91zqs,303
40
40
  primitive/hardware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- primitive/hardware/actions.py,sha256=fgwTASzElwk4PxLS2_sdIQYdwbRnuKczThV-aN_MT5A,19049
41
+ primitive/hardware/actions.py,sha256=jtthNgRyeRD8txt4WqEZskPtsDWU2Yg2gJZLSrEx1io,18603
42
42
  primitive/hardware/commands.py,sha256=_HaWOdRQSkhnA1xZZHZWgadSQ9Gijxtnzg2vc_IDSMA,1854
43
43
  primitive/hardware/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
- primitive/hardware/graphql/fragments.py,sha256=2uI0_WIhJISgd9Yx8tAdM7EUuAXEeQMUIXTIfkbZc2Q,246
44
+ primitive/hardware/graphql/fragments.py,sha256=PuqhW42fKUvRqOli5W7nOs2RfJ8FruSQC1gKBp3psBQ,271
45
45
  primitive/hardware/graphql/mutations.py,sha256=Zd6HxnIgTJ9mJQAfKJkdeDfstcPAal6Bj38pnKb_RuI,904
46
- primitive/hardware/graphql/queries.py,sha256=1xEe8JoXt_MmqJ3bIeCk13PpzyNFJn4OgRDU2_93mZA,574
46
+ primitive/hardware/graphql/queries.py,sha256=dhihQwr4O7zxDNRjeNWhkAXaSDOBsK-uqIczEGy1XLI,430
47
47
  primitive/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  primitive/jobs/actions.py,sha256=CtyO-Z9614TgIoXJJX1QGsoll0fgpBIjG9PJH5JwCQs,4901
49
49
  primitive/jobs/commands.py,sha256=MxPCkBEYW_eLNqgCRYeyj7ZcLOFAWfpVZlqDR2Y_S0o,830
@@ -68,11 +68,15 @@ primitive/projects/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
68
68
  primitive/projects/graphql/fragments.py,sha256=02F5nyI8i-ML_bV5FFHUgFWM5bBBfjmz_tkP-4QOXjU,127
69
69
  primitive/projects/graphql/mutations.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
70
  primitive/projects/graphql/queries.py,sha256=nFaVf6YOHA2L_FTgIUdRK-80hYTmv1a1X5ac7QPMp1k,646
71
+ primitive/provisioning/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
+ primitive/provisioning/actions.py,sha256=IYZYAbtomtZtlkqDaBxx4e7PFKGkRNqek_tABH6q_zY,2116
73
+ primitive/provisioning/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
+ primitive/provisioning/graphql/queries.py,sha256=cBtuKa6shoatYZfKSnQoPJP6B8g8y3QhFqJ_pkvMcG0,134
71
75
  primitive/reservations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
76
  primitive/reservations/actions.py,sha256=XjjF0UJAgKryuSJqakLMAWshZIbuM-DkTmdU95cANs4,4434
73
77
  primitive/reservations/commands.py,sha256=OwWWE9DrvtrVBcBki0bKTOqCzCQk090c0rPIAt89JLY,2243
74
78
  primitive/reservations/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- primitive/reservations/graphql/fragments.py,sha256=OPh8ylJR2kxfArBJ4IYIBLvWJyms3A2jVNNFLkTroRM,474
79
+ primitive/reservations/graphql/fragments.py,sha256=_TQfJeHky-Hh3WCHWobQ6-A1lpSvU-YkS0V9cqj2nOU,476
76
80
  primitive/reservations/graphql/mutations.py,sha256=IqzwQL7OclN7RpIcidrTQo9cGYofY7wqoBOdnY0pwN8,651
77
81
  primitive/reservations/graphql/queries.py,sha256=x31wTRelskX2fc0fx2qrY7XT1q74nvzLv_Xef3o9weg,746
78
82
  primitive/sim/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -89,8 +93,8 @@ primitive/utils/memory_size.py,sha256=4xfha21kW82nFvOTtDFx9Jk2ZQoEhkfXii-PGNTpIU
89
93
  primitive/utils/printer.py,sha256=f1XUpqi5dkTL3GWvYRUGlSwtj2IxU1q745T4Fxo7Tn4,370
90
94
  primitive/utils/shell.py,sha256=j7E1YwgNWw57dFHVfEbqRNVcPHX0xDefX2vFSNgeI_8,1648
91
95
  primitive/utils/verible.py,sha256=Zb5NUISvcaIgEvgCDBWr-GCoceMa79Tcwvr5Wl9lfnA,2252
92
- primitive-0.1.62.dist-info/METADATA,sha256=sQ2iai9V1lS1U_snKtzwP4JsUgUaHPYyqzoRnmaHVhk,3811
93
- primitive-0.1.62.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
94
- primitive-0.1.62.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
95
- primitive-0.1.62.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
96
- primitive-0.1.62.dist-info/RECORD,,
96
+ primitive-0.1.63.dist-info/METADATA,sha256=o-IZgpjA7lYJYn-sxuRBDA4EXxHA_c57G1U8Q3dcZzE,3774
97
+ primitive-0.1.63.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
98
+ primitive-0.1.63.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
99
+ primitive-0.1.63.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
100
+ primitive-0.1.63.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.26.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any