primitive 0.2.10__py3-none-any.whl → 0.2.12__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 +1 -1
- primitive/agent/actions.py +62 -120
- primitive/agent/commands.py +2 -1
- primitive/agent/runner.py +43 -34
- primitive/agent/uploader.py +2 -2
- primitive/cli.py +2 -0
- primitive/client.py +41 -16
- primitive/daemons/actions.py +48 -62
- primitive/daemons/commands.py +68 -22
- primitive/daemons/launch_agents.py +205 -122
- primitive/daemons/launch_service.py +224 -164
- primitive/daemons/ui.py +41 -0
- primitive/db/base.py +5 -0
- primitive/db/models.py +88 -0
- primitive/db/sqlite.py +34 -0
- primitive/exec/actions.py +0 -1
- primitive/files/actions.py +0 -1
- primitive/hardware/actions.py +11 -10
- primitive/hardware/commands.py +1 -68
- primitive/hardware/ui.py +67 -0
- primitive/monitor/actions.py +199 -0
- primitive/monitor/commands.py +13 -0
- primitive/reservations/actions.py +0 -2
- primitive/utils/auth.py +0 -2
- primitive/utils/daemons.py +54 -0
- {primitive-0.2.10.dist-info → primitive-0.2.12.dist-info}/METADATA +3 -1
- {primitive-0.2.10.dist-info → primitive-0.2.12.dist-info}/RECORD +30 -22
- {primitive-0.2.10.dist-info → primitive-0.2.12.dist-info}/WHEEL +0 -0
- {primitive-0.2.10.dist-info → primitive-0.2.12.dist-info}/entry_points.txt +0 -0
- {primitive-0.2.10.dist-info → primitive-0.2.12.dist-info}/licenses/LICENSE.txt +0 -0
primitive/hardware/commands.py
CHANGED
@@ -3,13 +3,11 @@ import typing
|
|
3
3
|
import click
|
4
4
|
|
5
5
|
from ..utils.printer import print_result
|
6
|
+
from .ui import render_hardware_table
|
6
7
|
|
7
8
|
if typing.TYPE_CHECKING:
|
8
9
|
from ..client import Primitive
|
9
10
|
|
10
|
-
from rich.console import Console
|
11
|
-
from rich.table import Table
|
12
|
-
|
13
11
|
|
14
12
|
@click.group()
|
15
13
|
@click.pass_context
|
@@ -71,71 +69,6 @@ def checkin_command(context):
|
|
71
69
|
print_result(message=message, context=context, fg="green")
|
72
70
|
|
73
71
|
|
74
|
-
def hardware_status_string(hardware):
|
75
|
-
if activeReservation := hardware.get("activeReservation"):
|
76
|
-
if activeReservation.get("status", None) == "in_progress":
|
77
|
-
return "Reserved"
|
78
|
-
if hardware.get("isQuarantined"):
|
79
|
-
return "Quarantined"
|
80
|
-
if not hardware.get("isOnline"):
|
81
|
-
return "Offline"
|
82
|
-
if not hardware.get("isHealthy"):
|
83
|
-
return "Not healthy"
|
84
|
-
if not hardware.get("isAvailable"):
|
85
|
-
return "Not available"
|
86
|
-
else:
|
87
|
-
return "Available"
|
88
|
-
|
89
|
-
|
90
|
-
def render_hardware_table(hardware_list):
|
91
|
-
console = Console()
|
92
|
-
|
93
|
-
table = Table(show_header=True, header_style="bold magenta")
|
94
|
-
table.add_column("Organization")
|
95
|
-
table.add_column("Name | Slug")
|
96
|
-
table.add_column("Status")
|
97
|
-
table.add_column("Reservation")
|
98
|
-
|
99
|
-
for hardware in hardware_list:
|
100
|
-
name = hardware.get("name")
|
101
|
-
slug = hardware.get("slug")
|
102
|
-
print_name = name
|
103
|
-
if name != slug:
|
104
|
-
print_name = f"{name} | {slug}"
|
105
|
-
child_table = Table(show_header=False, header_style="bold magenta")
|
106
|
-
child_table.add_column("Organization")
|
107
|
-
child_table.add_column("Name | Slug")
|
108
|
-
child_table.add_column("Status")
|
109
|
-
child_table.add_column("Reservation", justify="right")
|
110
|
-
|
111
|
-
table.add_row(
|
112
|
-
hardware.get("organization").get("name"),
|
113
|
-
print_name,
|
114
|
-
hardware_status_string(hardware),
|
115
|
-
f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
|
116
|
-
if hardware.get("activeReservation", None)
|
117
|
-
else "",
|
118
|
-
)
|
119
|
-
|
120
|
-
if len(hardware.get("children", [])) > 0:
|
121
|
-
for child in hardware.get("children"):
|
122
|
-
name = child.get("name")
|
123
|
-
slug = child.get("slug")
|
124
|
-
print_name = name
|
125
|
-
if name != slug:
|
126
|
-
print_name = f"└── {name} | {slug}"
|
127
|
-
table.add_row(
|
128
|
-
hardware.get("organization").get("name"),
|
129
|
-
print_name,
|
130
|
-
hardware_status_string(hardware),
|
131
|
-
f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
|
132
|
-
if hardware.get("activeReservation", None)
|
133
|
-
else "",
|
134
|
-
)
|
135
|
-
|
136
|
-
console.print(table)
|
137
|
-
|
138
|
-
|
139
72
|
@cli.command("list")
|
140
73
|
@click.pass_context
|
141
74
|
def list_command(context):
|
primitive/hardware/ui.py
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
from rich.console import Console
|
2
|
+
from rich.table import Table
|
3
|
+
|
4
|
+
|
5
|
+
def render_hardware_table(hardware_list) -> None:
|
6
|
+
console = Console()
|
7
|
+
|
8
|
+
table = Table(show_header=True, header_style="bold #FFA800")
|
9
|
+
table.add_column("Organization")
|
10
|
+
table.add_column("Name | Slug")
|
11
|
+
table.add_column("Status")
|
12
|
+
table.add_column("Reservation")
|
13
|
+
|
14
|
+
for hardware in hardware_list:
|
15
|
+
name = hardware.get("name")
|
16
|
+
slug = hardware.get("slug")
|
17
|
+
print_name = name
|
18
|
+
if name != slug:
|
19
|
+
print_name = f"{name} | {slug}"
|
20
|
+
child_table = Table(show_header=False, header_style="bold #FFA800")
|
21
|
+
child_table.add_column("Organization")
|
22
|
+
child_table.add_column("Name | Slug")
|
23
|
+
child_table.add_column("Status")
|
24
|
+
child_table.add_column("Reservation", justify="right")
|
25
|
+
|
26
|
+
table.add_row(
|
27
|
+
hardware.get("organization").get("name"),
|
28
|
+
print_name,
|
29
|
+
hardware_status_string(hardware),
|
30
|
+
f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
|
31
|
+
if hardware.get("activeReservation", None)
|
32
|
+
else "",
|
33
|
+
)
|
34
|
+
|
35
|
+
if len(hardware.get("children", [])) > 0:
|
36
|
+
for child in hardware.get("children"):
|
37
|
+
name = child.get("name")
|
38
|
+
slug = child.get("slug")
|
39
|
+
print_name = name
|
40
|
+
if name != slug:
|
41
|
+
print_name = f"└── {name} | {slug}"
|
42
|
+
table.add_row(
|
43
|
+
hardware.get("organization").get("name"),
|
44
|
+
print_name,
|
45
|
+
hardware_status_string(hardware),
|
46
|
+
f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
|
47
|
+
if hardware.get("activeReservation", None)
|
48
|
+
else "",
|
49
|
+
)
|
50
|
+
|
51
|
+
console.print(table)
|
52
|
+
|
53
|
+
|
54
|
+
def hardware_status_string(hardware) -> str:
|
55
|
+
if activeReservation := hardware.get("activeReservation"):
|
56
|
+
if activeReservation.get("status", None) == "in_progress":
|
57
|
+
return "Reserved"
|
58
|
+
if hardware.get("isQuarantined"):
|
59
|
+
return "Quarantined"
|
60
|
+
if not hardware.get("isOnline"):
|
61
|
+
return "Offline"
|
62
|
+
if not hardware.get("isHealthy"):
|
63
|
+
return "Not healthy"
|
64
|
+
if not hardware.get("isAvailable"):
|
65
|
+
return "Not available"
|
66
|
+
else:
|
67
|
+
return "Available"
|
@@ -0,0 +1,199 @@
|
|
1
|
+
import sys
|
2
|
+
from time import sleep
|
3
|
+
|
4
|
+
import psutil
|
5
|
+
from loguru import logger
|
6
|
+
|
7
|
+
from primitive.__about__ import __version__
|
8
|
+
from primitive.db import sqlite
|
9
|
+
from primitive.db.models import JobRun
|
10
|
+
from primitive.utils.actions import BaseAction
|
11
|
+
from primitive.utils.exceptions import P_CLI_100
|
12
|
+
|
13
|
+
|
14
|
+
class Monitor(BaseAction):
|
15
|
+
def start(self):
|
16
|
+
logger.remove()
|
17
|
+
logger.add(
|
18
|
+
sink=sys.stderr,
|
19
|
+
format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <level>{message}</level>",
|
20
|
+
backtrace=True,
|
21
|
+
diagnose=True,
|
22
|
+
level="DEBUG" if self.primitive.DEBUG else "INFO",
|
23
|
+
)
|
24
|
+
logger.info("[*] primitive monitor")
|
25
|
+
logger.info(f"[*] Version: {__version__}")
|
26
|
+
|
27
|
+
try:
|
28
|
+
# hey stupid:
|
29
|
+
# do not set is_available to True here, it will mess up the reservation logic
|
30
|
+
# only set is_available after we've checked that no active reservation is present
|
31
|
+
# setting is_available of the parent also effects the children,
|
32
|
+
# which may have active reservations as well
|
33
|
+
self.primitive.hardware.check_in_http(is_online=True)
|
34
|
+
except Exception as exception:
|
35
|
+
logger.exception(f"Error checking in hardware: {exception}")
|
36
|
+
sys.exit(1)
|
37
|
+
|
38
|
+
# Initialize the database
|
39
|
+
sqlite.init()
|
40
|
+
|
41
|
+
try:
|
42
|
+
active_reservation_id = None
|
43
|
+
active_reservation_pk = None
|
44
|
+
|
45
|
+
while True:
|
46
|
+
# FIRST, check for jobs in the database that are running
|
47
|
+
db_job_runs = JobRun.objects.all()
|
48
|
+
for job_run in db_job_runs:
|
49
|
+
if job_run.pid is None:
|
50
|
+
pid_sleep_amount = 0.1
|
51
|
+
logger.debug(
|
52
|
+
f"Job run {job_run.job_run_id} has no PID. Agent has not started."
|
53
|
+
)
|
54
|
+
logger.debug(
|
55
|
+
f"Sleeping {pid_sleep_amount} seconds before checking again..."
|
56
|
+
)
|
57
|
+
sleep(pid_sleep_amount)
|
58
|
+
continue
|
59
|
+
|
60
|
+
logger.debug(
|
61
|
+
f"Checking process PID {job_run.pid} for JobRun {job_run.job_run_id}..."
|
62
|
+
)
|
63
|
+
|
64
|
+
status = self.primitive.jobs.get_job_status(job_run.job_run_id)
|
65
|
+
if status is None or status.data is None:
|
66
|
+
logger.error(
|
67
|
+
f"Error fetching status of <JobRun {job_run.job_run_id}>."
|
68
|
+
)
|
69
|
+
continue
|
70
|
+
|
71
|
+
status_value = status.data["jobRun"]["status"]
|
72
|
+
conclusion_value = status.data["jobRun"]["conclusion"]
|
73
|
+
|
74
|
+
logger.debug(f"- Status: {status_value}")
|
75
|
+
logger.debug(f"- Conclusion: {conclusion_value}")
|
76
|
+
|
77
|
+
try:
|
78
|
+
parent = psutil.Process(job_run.pid)
|
79
|
+
except psutil.NoSuchProcess:
|
80
|
+
logger.debug("Process not found")
|
81
|
+
continue
|
82
|
+
|
83
|
+
children = parent.children(recursive=True)
|
84
|
+
|
85
|
+
if status_value == "completed" and conclusion_value == "cancelled":
|
86
|
+
logger.warning("Job cancelled by user")
|
87
|
+
for child in children:
|
88
|
+
logger.debug(f"Killing child process {child.pid}...")
|
89
|
+
child.kill()
|
90
|
+
|
91
|
+
logger.debug(f"Killing parent process {parent.pid}...")
|
92
|
+
parent.kill()
|
93
|
+
|
94
|
+
if status != "completed":
|
95
|
+
sleep(1)
|
96
|
+
continue
|
97
|
+
|
98
|
+
# Second, check for active reservations
|
99
|
+
hardware = self.primitive.hardware.get_own_hardware_details()
|
100
|
+
if hardware["activeReservation"]:
|
101
|
+
if (
|
102
|
+
hardware["activeReservation"]["id"] != active_reservation_id
|
103
|
+
or hardware["activeReservation"]["pk"] != active_reservation_pk
|
104
|
+
):
|
105
|
+
logger.info("New reservation for this hardware.")
|
106
|
+
active_reservation_id = hardware["activeReservation"]["id"]
|
107
|
+
active_reservation_pk = hardware["activeReservation"]["pk"]
|
108
|
+
logger.debug("Active Reservation:")
|
109
|
+
logger.debug(f"Node ID: {active_reservation_id}")
|
110
|
+
logger.debug(f"PK: {active_reservation_pk}")
|
111
|
+
|
112
|
+
logger.debug("Running pre provisioning steps for reservation.")
|
113
|
+
self.primitive.provisioning.add_reservation_authorized_keys(
|
114
|
+
reservation_id=active_reservation_id
|
115
|
+
)
|
116
|
+
|
117
|
+
if not active_reservation_id:
|
118
|
+
self.primitive.hardware.check_in_http(
|
119
|
+
is_available=True, is_online=True
|
120
|
+
)
|
121
|
+
logger.debug("Syncing children...")
|
122
|
+
self.primitive.hardware._sync_children(hardware=hardware)
|
123
|
+
|
124
|
+
sleep_amount = 5
|
125
|
+
logger.debug(
|
126
|
+
f"No active reservation found... [sleeping {sleep_amount} seconds]"
|
127
|
+
)
|
128
|
+
sleep(sleep_amount)
|
129
|
+
continue
|
130
|
+
else:
|
131
|
+
if (
|
132
|
+
hardware["activeReservation"] is None
|
133
|
+
and active_reservation_id is not None
|
134
|
+
# and hardware["isAvailable"] NOTE: this condition was causing the CLI to get into a loop searching for job runs
|
135
|
+
):
|
136
|
+
logger.debug("Previous Reservation is Complete:")
|
137
|
+
logger.debug(f"Node ID: {active_reservation_id}")
|
138
|
+
logger.debug(f"PK: {active_reservation_pk}")
|
139
|
+
logger.debug(
|
140
|
+
"Running cleanup provisioning steps for reservation."
|
141
|
+
)
|
142
|
+
self.primitive.provisioning.remove_reservation_authorized_keys(
|
143
|
+
reservation_id=active_reservation_id
|
144
|
+
)
|
145
|
+
active_reservation_id = None
|
146
|
+
active_reservation_pk = None
|
147
|
+
|
148
|
+
# Third, see if the active reservation has any pending job runs
|
149
|
+
job_runs_for_reservation = self.primitive.jobs.get_job_runs(
|
150
|
+
status="pending", first=1, reservation_id=active_reservation_id
|
151
|
+
)
|
152
|
+
|
153
|
+
if (
|
154
|
+
job_runs_for_reservation is None
|
155
|
+
or job_runs_for_reservation.data is None
|
156
|
+
):
|
157
|
+
logger.error("Error fetching job runs.")
|
158
|
+
sleep_amount = 5
|
159
|
+
logger.debug(
|
160
|
+
f"Error fetching job runs... [sleeping {sleep_amount} seconds]"
|
161
|
+
)
|
162
|
+
sleep(sleep_amount)
|
163
|
+
continue
|
164
|
+
|
165
|
+
pending_job_runs = [
|
166
|
+
edge["node"]
|
167
|
+
for edge in job_runs_for_reservation.data["jobRuns"]["edges"]
|
168
|
+
]
|
169
|
+
|
170
|
+
if not pending_job_runs:
|
171
|
+
self.primitive.hardware.check_in_http(
|
172
|
+
is_available=False, is_online=True
|
173
|
+
)
|
174
|
+
sleep_amount = 5
|
175
|
+
logger.debug(
|
176
|
+
f"Waiting for Job Runs... [sleeping {sleep_amount} seconds]"
|
177
|
+
)
|
178
|
+
sleep(sleep_amount)
|
179
|
+
continue
|
180
|
+
|
181
|
+
# If we did find a pending job run, check if it exists in the database
|
182
|
+
# and create it if it doesn't.
|
183
|
+
# This will trigger the agent to start the job run.
|
184
|
+
job_run = pending_job_runs[0]
|
185
|
+
if not JobRun.objects.filter_by(job_run_id=job_run["id"]).exists():
|
186
|
+
JobRun.objects.create(job_run_id=job_run["id"], pid=None)
|
187
|
+
logger.debug(f"Creating job run in database: {job_run['id']}")
|
188
|
+
|
189
|
+
except KeyboardInterrupt:
|
190
|
+
logger.info("[*] Stopping primitive monitor...")
|
191
|
+
try:
|
192
|
+
self.primitive.hardware.check_in_http(
|
193
|
+
is_available=False, is_online=False, stopping_agent=True
|
194
|
+
)
|
195
|
+
|
196
|
+
except P_CLI_100 as exception:
|
197
|
+
logger.error("[*] Error stopping primitive monitor.")
|
198
|
+
logger.error(str(exception))
|
199
|
+
sys.exit()
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import click
|
2
|
+
import typing
|
3
|
+
|
4
|
+
if typing.TYPE_CHECKING:
|
5
|
+
from ..client import Primitive
|
6
|
+
|
7
|
+
|
8
|
+
@click.command("monitor")
|
9
|
+
@click.pass_context
|
10
|
+
def cli(context):
|
11
|
+
"""monitor"""
|
12
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
13
|
+
primitive.monitor.start()
|
@@ -89,7 +89,6 @@ class Reservations(BaseAction):
|
|
89
89
|
)
|
90
90
|
if messages := result.data.get("reservationCreate").get("messages"):
|
91
91
|
for message in messages:
|
92
|
-
logger.enable("primitive")
|
93
92
|
if message.get("kind") == "ERROR":
|
94
93
|
logger.error(message.get("message"))
|
95
94
|
else:
|
@@ -141,7 +140,6 @@ class Reservations(BaseAction):
|
|
141
140
|
reservation = reservation_result.data["reservation"]
|
142
141
|
current_status = reservation["status"]
|
143
142
|
|
144
|
-
logger.enable("primitive")
|
145
143
|
logger.debug(
|
146
144
|
f"Waiting {total_sleep_time}s for reservation {reservation_id} to be in_progress."
|
147
145
|
)
|
primitive/utils/auth.py
CHANGED
@@ -11,7 +11,6 @@ MAX_TIME_FOR_BACKOFF = 60 * 15 # 15 minutes
|
|
11
11
|
|
12
12
|
|
13
13
|
def connection_backoff_handler(details):
|
14
|
-
logger.enable("primitive")
|
15
14
|
logger.error(
|
16
15
|
"Cannot connect to API. Waiting {wait:0.1f} seconds after {tries} tries.".format(
|
17
16
|
**details
|
@@ -25,7 +24,6 @@ def create_new_session(primitive):
|
|
25
24
|
fingerprint = primitive.host_config.get("fingerprint")
|
26
25
|
|
27
26
|
if not token or not transport:
|
28
|
-
logger.enable("primitive")
|
29
27
|
logger.error(
|
30
28
|
"CLI is not configured. Run `primitive config` to add an auth token."
|
31
29
|
)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
|
4
|
+
|
5
|
+
class Daemon(ABC):
|
6
|
+
name: str
|
7
|
+
label: str
|
8
|
+
|
9
|
+
@property
|
10
|
+
@abstractmethod
|
11
|
+
def logs(self) -> Path:
|
12
|
+
"""Path to to agent or service logs"""
|
13
|
+
pass
|
14
|
+
|
15
|
+
@property
|
16
|
+
@abstractmethod
|
17
|
+
def file_path(self) -> Path:
|
18
|
+
"""Path to agent or service definition file"""
|
19
|
+
pass
|
20
|
+
|
21
|
+
@abstractmethod
|
22
|
+
def install(self) -> bool:
|
23
|
+
"""Install the daemon"""
|
24
|
+
pass
|
25
|
+
|
26
|
+
@abstractmethod
|
27
|
+
def uninstall(self) -> bool:
|
28
|
+
"""Uninstall the daemon"""
|
29
|
+
pass
|
30
|
+
|
31
|
+
@abstractmethod
|
32
|
+
def start(self) -> bool:
|
33
|
+
"""Start the daemon"""
|
34
|
+
pass
|
35
|
+
|
36
|
+
@abstractmethod
|
37
|
+
def stop(self) -> bool:
|
38
|
+
"""Stop the daemon"""
|
39
|
+
pass
|
40
|
+
|
41
|
+
@abstractmethod
|
42
|
+
def is_installed(self) -> bool:
|
43
|
+
"""Check if the daemon is installed"""
|
44
|
+
pass
|
45
|
+
|
46
|
+
@abstractmethod
|
47
|
+
def is_active(self) -> bool:
|
48
|
+
"""Check if the daemon is active"""
|
49
|
+
pass
|
50
|
+
|
51
|
+
@abstractmethod
|
52
|
+
def view_logs(self) -> None:
|
53
|
+
"""View the daemon logs"""
|
54
|
+
pass
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: primitive
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.12
|
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
|
@@ -23,9 +23,11 @@ Requires-Dist: gql[all]
|
|
23
23
|
Requires-Dist: loguru
|
24
24
|
Requires-Dist: paramiko[invoke]
|
25
25
|
Requires-Dist: primitive-pal==0.1.4
|
26
|
+
Requires-Dist: psutil>=7.0.0
|
26
27
|
Requires-Dist: pyyaml
|
27
28
|
Requires-Dist: rich>=13.9.4
|
28
29
|
Requires-Dist: speedtest-cli
|
30
|
+
Requires-Dist: sqlalchemy>=2.0.40
|
29
31
|
Description-Content-Type: text/markdown
|
30
32
|
|
31
33
|
# primitive
|
@@ -1,28 +1,32 @@
|
|
1
|
-
primitive/__about__.py,sha256=
|
1
|
+
primitive/__about__.py,sha256=ZJWGMrU4ZWd5v5sybxqbMIUQbxi44Ln1dT1SjERj8jk,130
|
2
2
|
primitive/__init__.py,sha256=bwKdgggKNVssJFVPfKSxqFMz4IxSr54WWbmiZqTMPNI,106
|
3
|
-
primitive/cli.py,sha256=
|
4
|
-
primitive/client.py,sha256=
|
3
|
+
primitive/cli.py,sha256=g7EtHI9MATAB0qQu5w-WzbXtxz_8zu8z5E7sETmMkKU,2509
|
4
|
+
primitive/client.py,sha256=h8WZVnQylVe0vbpuyC8YZHl2JyITSPC-1HbUcmrE5pc,3623
|
5
5
|
primitive/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
primitive/agent/actions.py,sha256=
|
7
|
-
primitive/agent/commands.py,sha256
|
8
|
-
primitive/agent/runner.py,sha256=
|
9
|
-
primitive/agent/uploader.py,sha256=
|
6
|
+
primitive/agent/actions.py,sha256=PzFOgxuRrhbUGpUygnTZVru58Fv87GI8tgJYkZB1LjI,3773
|
7
|
+
primitive/agent/commands.py,sha256=cK7d3OcN5Z65gQWVZFQ-Y9ddw9Pes4f9OVBpeMsj5sE,255
|
8
|
+
primitive/agent/runner.py,sha256=CoRyReO3jPV8B7vILVWdszFD4GVop7HsVEUo1hoRXjo,14556
|
9
|
+
primitive/agent/uploader.py,sha256=ZzrzsajNBogwEC7mT6Ejy0h2Jd9axMYGzt9pbCvVMlk,3171
|
10
10
|
primitive/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
primitive/auth/actions.py,sha256=MPsG9LcKcOPwA7gZ9Ewk0PZJhTQvIrGfODdz4GxSzgA,999
|
12
12
|
primitive/auth/commands.py,sha256=2z5u5xX64n0yILucx9emtWh3uQXLvs2QQQQIldZGr94,2341
|
13
13
|
primitive/auth/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
14
|
primitive/auth/graphql/queries.py,sha256=jhrr_VFzHIn8vcVprMIzUx7V4kkWYdR6CKMKPoVFv60,180
|
15
15
|
primitive/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
-
primitive/daemons/actions.py,sha256=
|
17
|
-
primitive/daemons/commands.py,sha256
|
18
|
-
primitive/daemons/launch_agents.py,sha256=
|
19
|
-
primitive/daemons/launch_service.py,sha256=
|
16
|
+
primitive/daemons/actions.py,sha256=V4BUCLS8UoQOZoS2vwEkYQpWAUNdZnMPBhQR19RvQXs,2023
|
17
|
+
primitive/daemons/commands.py,sha256=Xt4qFymNrDLdHJhRnEH_4Re-2xX6w1OT-chV9k7dFCs,2670
|
18
|
+
primitive/daemons/launch_agents.py,sha256=KD7cqQZDtfDmMyNiYrswTRWEktvS9A1QsqQF1jhMDjw,7940
|
19
|
+
primitive/daemons/launch_service.py,sha256=IhvKZqU5juA3hKsvUB2275BP8lNBl5XWkVoqVgdwy-o,8013
|
20
|
+
primitive/daemons/ui.py,sha256=Af3OJWJ0jdGlb1nfA5yaGYdhBEqqpM8zP2U2vUQdCbw,1236
|
21
|
+
primitive/db/base.py,sha256=mH7f2d_jiyxJSSx9Gk53QBXRa3LiKBsBjkFgvmtH1WA,83
|
22
|
+
primitive/db/models.py,sha256=GfnJdAq4Tb68CI4BKAuJDZVqioGavveaAHbCPeLNngw,2840
|
23
|
+
primitive/db/sqlite.py,sha256=3V9ZxbgME1ThfJp90MPLUxU8b9imgNZM5CHOnA-WkaQ,953
|
20
24
|
primitive/exec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
|
-
primitive/exec/actions.py,sha256=
|
25
|
+
primitive/exec/actions.py,sha256=4d_TCjNDcVFoZ9Zw7ZuBa6hKMv2Xzm7_UX_8wcX1aSk,4124
|
22
26
|
primitive/exec/commands.py,sha256=66LO2kkJC-ynNZQpUCXv4Ol15QoacdSZAHblePDcmLo,510
|
23
27
|
primitive/exec/interactive.py,sha256=TscY6s2ZysijidKPheq6y-fCErUVLS0zcdTW8XyFWGI,2435
|
24
28
|
primitive/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
|
-
primitive/files/actions.py,sha256=
|
29
|
+
primitive/files/actions.py,sha256=jvsBivYBmPeqb6Ge7gECm_x20AFUL7UYPGJJFmoCeOM,12409
|
26
30
|
primitive/files/commands.py,sha256=ZNW4y8JZF1li7P5ej1r-Xcqu0iGpRRlMYvthuZOLLbQ,1163
|
27
31
|
primitive/files/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
32
|
primitive/files/graphql/fragments.py,sha256=II6WHZjzSqX4IELwdiWokqHTKvDq6mMHF5gp3rLnj3U,231
|
@@ -38,9 +42,10 @@ primitive/graphql/relay.py,sha256=bmij2AjdpURQ6GGVCxwWhauF-r_SxuAU2oJ4sDbLxpI,72
|
|
38
42
|
primitive/graphql/sdk.py,sha256=KhVWDZms_eMBgt6ftSJitRALguagy-nmrj4IC2taeXY,1535
|
39
43
|
primitive/graphql/utility_fragments.py,sha256=uIjwILC4QtWNyO5vu77VjQf_p0jvP3A9q_6zRq91zqs,303
|
40
44
|
primitive/hardware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
|
-
primitive/hardware/actions.py,sha256=
|
45
|
+
primitive/hardware/actions.py,sha256=d5KwuSsceOhDH9rgOL7YTCpQPhqT2inRTiZnROtiDic,26076
|
42
46
|
primitive/hardware/android.py,sha256=tu7pBPxWFrIwb_mm5CEdFFf1_veNDOKjOCQg13i_Lh4,2758
|
43
|
-
primitive/hardware/commands.py,sha256=
|
47
|
+
primitive/hardware/commands.py,sha256=ixMPhDOpsU-eONxmimqKVynus-Eaq2XPKEK017WM_rM,3229
|
48
|
+
primitive/hardware/ui.py,sha256=12rucuZ2s-w5R4bKyxON5dEbrdDnVf5sbj3K_nbdo44,2473
|
44
49
|
primitive/hardware/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
45
50
|
primitive/hardware/graphql/fragments.py,sha256=kI6qnTNjaEaUr-C6eD55COphtueVYbYOWZwN5EW_3qw,350
|
46
51
|
primitive/hardware/graphql/mutations.py,sha256=_4Hkbfik9Ron4T-meulu6T-9FR_BZjyPNwn745MPksU,1484
|
@@ -52,6 +57,8 @@ primitive/jobs/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
52
57
|
primitive/jobs/graphql/fragments.py,sha256=1_ZttT7dx36KDC3DClJz9M8LMpsPwXySBygHSiUEcGg,619
|
53
58
|
primitive/jobs/graphql/mutations.py,sha256=8ASvCmwQh7cMeeiykOdYaYVryG8FRIuVF6v_J8JJZuw,219
|
54
59
|
primitive/jobs/graphql/queries.py,sha256=BrU_GnLjK0bTAmWsLSmGEUea7EM8MqTKxN1Qp6sSjwc,1597
|
60
|
+
primitive/monitor/actions.py,sha256=GUQrwuan82pOJ5gI2FvQYzgDoP4fs28PdcI_fg_aXRs,8692
|
61
|
+
primitive/monitor/commands.py,sha256=dZsD8WKGU4OYO_AlKawfeRNVTMN0xJ-DFRkmKTS464s,258
|
55
62
|
primitive/organizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
63
|
primitive/organizations/actions.py,sha256=Tgp_rox0jcvfhQ-LmcWc9vkPdeJu5Bk6U1rNuT9oDnw,1088
|
57
64
|
primitive/organizations/commands.py,sha256=_dwgVEJCqMa5VgB_7P1wLPFc0AuT1p9dtyR9JRr4kpw,487
|
@@ -71,7 +78,7 @@ primitive/provisioning/actions.py,sha256=IYZYAbtomtZtlkqDaBxx4e7PFKGkRNqek_tABH6
|
|
71
78
|
primitive/provisioning/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
72
79
|
primitive/provisioning/graphql/queries.py,sha256=cBtuKa6shoatYZfKSnQoPJP6B8g8y3QhFqJ_pkvMcG0,134
|
73
80
|
primitive/reservations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74
|
-
primitive/reservations/actions.py,sha256=
|
81
|
+
primitive/reservations/actions.py,sha256=FiodRTVUgGgFfoksnN9W0XNdGTd2AxPJTfUrZbmQ0_g,6179
|
75
82
|
primitive/reservations/commands.py,sha256=LFRoV59QGgWIjBdrGjJdffHugg8TLe0Fwlcyu_JaTkk,2369
|
76
83
|
primitive/reservations/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
77
84
|
primitive/reservations/graphql/fragments.py,sha256=o5JXkhrFrftYZbsmOQRj105bNw4WwO6U34yN0X-pbCg,411
|
@@ -79,17 +86,18 @@ primitive/reservations/graphql/mutations.py,sha256=IqzwQL7OclN7RpIcidrTQo9cGYofY
|
|
79
86
|
primitive/reservations/graphql/queries.py,sha256=x31wTRelskX2fc0fx2qrY7XT1q74nvzLv_Xef3o9weg,746
|
80
87
|
primitive/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
81
88
|
primitive/utils/actions.py,sha256=HOFrmM3-0A_A3NS84MqrZ6JmQEiiPSoDqEeuu6b_qfQ,196
|
82
|
-
primitive/utils/auth.py,sha256=
|
89
|
+
primitive/utils/auth.py,sha256=uBIZNPF2CpbaPV2UMi6eWVUKghV6WIm-pG3-UM29bNs,1465
|
83
90
|
primitive/utils/cache.py,sha256=FHGmVWYLJFQOazpXXcEwI0YJEZbdkgG39nOLdOv6VNk,1575
|
84
91
|
primitive/utils/chunk_size.py,sha256=PAuVuirUTA9oRXyjo1c6MWxo31WVBRkWMuWw-AS58Bw,2914
|
85
92
|
primitive/utils/config.py,sha256=DlFM5Nglo22WPtbpZSVtH7NX-PTMaKYlcrUE7GPRG4c,1058
|
93
|
+
primitive/utils/daemons.py,sha256=YkG-OcrTxMhGedbNJMKLq_e7CdTy30Ba2oCVUY-09Co,1086
|
86
94
|
primitive/utils/exceptions.py,sha256=DrYHTcCAJGC7cCUwOx_FmdlVLWRdpzvDvpLb82heppE,311
|
87
95
|
primitive/utils/memory_size.py,sha256=4xfha21kW82nFvOTtDFx9Jk2ZQoEhkfXii-PGNTpIUk,3058
|
88
96
|
primitive/utils/printer.py,sha256=f1XUpqi5dkTL3GWvYRUGlSwtj2IxU1q745T4Fxo7Tn4,370
|
89
97
|
primitive/utils/shell.py,sha256=jWzb7ky7p987dJas6ZvarK3IJNZ5cwBXcryRWb9Uh6U,2072
|
90
98
|
primitive/utils/text.py,sha256=XiESMnlhjQ534xE2hMNf08WehE1SKaYFRNih0MmnK0k,829
|
91
|
-
primitive-0.2.
|
92
|
-
primitive-0.2.
|
93
|
-
primitive-0.2.
|
94
|
-
primitive-0.2.
|
95
|
-
primitive-0.2.
|
99
|
+
primitive-0.2.12.dist-info/METADATA,sha256=5GebdNRhv_zCe-W5OP_G7YDzDSzGVC1wA55M0NJdDlQ,3733
|
100
|
+
primitive-0.2.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
101
|
+
primitive-0.2.12.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
|
102
|
+
primitive-0.2.12.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
|
103
|
+
primitive-0.2.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|