Skip to content

Commit e1957f9

Browse files
authored
Merge pull request #103 from dominrios/issue/100_make_deploy_button_work
Issue/100 make deploy button work
2 parents 1258724 + 701b209 commit e1957f9

4 files changed

Lines changed: 127 additions & 34 deletions

File tree

volttron_installer/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class Instance(rx.Base):
99
platform: PlatformModelView
1010

1111
web_bind_address: str = "http://127.0.0.1:8080"
12+
password: str = ""
1213

1314
safe_host_entry: dict = {}
1415
uncaught: bool = False
@@ -21,6 +22,7 @@ class Instance(rx.Base):
2122
agent_configuration_expanded: bool = False
2223

2324
new_instance: bool = True
25+
deployed: bool = False
2426

2527
def has_uncaught_changes(self) -> bool:
2628
return self.host.to_dict() != self.safe_host_entry
@@ -42,6 +44,8 @@ def refresh_for_copy(self) -> None:
4244
"""
4345
self.new_instance = True
4446
self.platform.in_file = False
47+
self.deployed = False
48+
self.password = ""
4549
for agent in self.platform.agents.values():
4650
agent.in_file = False
4751
agent.selected_config_component_id = ""

volttron_installer/pages/platform_page.py

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -484,30 +484,75 @@ def configuration_tab_content() -> rx.Component:
484484
color_scheme="green",
485485
on_click=lambda: State.handle_save(),
486486
disabled=rx.cond(
487-
(State.instance_savable)
488-
& (State.instance_uncaught),
489-
# (working_platform.uncaught),
490-
False,
491-
True
492-
)
487+
(State.instance_savable)
488+
& (State.instance_uncaught),
489+
# (working_platform.uncaught),
490+
False,
491+
True
492+
)
493+
),
494+
rx.dialog.root(
495+
rx.dialog.trigger(
496+
rx.button(
497+
rx.cond(
498+
State.platform_deployed,
499+
"Re-Deploy",
500+
"Deploy"
501+
),
502+
size="4",
503+
variant="surface",
504+
color_scheme="blue",
505+
disabled=rx.cond(
506+
(State.instance_uncaught == False)
507+
& (State.instance_deployable==True),
508+
False,
509+
True
510+
)
511+
),
493512
),
494-
rx.button(
495-
rx.cond(
496-
State.platform_deployed,
497-
"Re-Deploy",
498-
"Deploy"
499-
),
500-
size="4",
501-
variant="surface",
502-
color_scheme="blue",
503-
on_click=lambda: State.handle_deploy(),
504-
disabled=rx.cond(
505-
(working_platform.uncaught == False)
506-
& (working_platform.valid==True),
507-
False,
508-
True
513+
rx.dialog.content(
514+
rx.dialog.title("Password Required"),
515+
rx.dialog.description("To deploy, please provide your ssh password"),
516+
rx.vstack(
517+
rx.vstack(
518+
form_entry.form_entry(
519+
"Password",
520+
rx.input(
521+
type="password",
522+
on_change=State.update_password_field,
523+
value=State.password_field
524+
),
525+
required_entry=True
526+
),
527+
align="center",
528+
justify="center"
529+
),
530+
rx.hstack(
531+
rx.dialog.close(
532+
rx.button(
533+
"Cancel",
534+
variant="soft",
535+
color_scheme="gray",
536+
)
537+
),
538+
rx.button(
539+
"Submit",
540+
on_click=lambda: State.handle_deploy(),
541+
disabled=rx.cond(
542+
State.password_field=="",
543+
True,
544+
False
545+
)
546+
),
547+
spacing="3",
548+
justify="end",
549+
),
550+
width="100%",
551+
padding_top="1rem",
552+
spacing="6"
509553
)
510-
),
554+
)
555+
),
511556
rx.button(
512557
"Cancel",
513558
size="4",
@@ -560,4 +605,3 @@ def agent_config_tile(text, left_component: rx.Component = False, right_componen
560605
spacing="2",
561606
align="center",
562607
)
563-

volttron_installer/state.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,23 @@ def platform_title(self) -> str:
241241
return working_platform.platform.safe_platform['config']['instance_name']
242242

243243
# === vars for platform details ===
244+
@rx.var
245+
def password_field(self) -> str:
246+
if self.current_uid == "":
247+
return ""
248+
working_platform: Instance | None = self.platforms.get(self.current_uid, None)
249+
if working_platform is None:
250+
return ""
251+
return working_platform.password
252+
244253
@rx.var
245254
def platform_deployed(self) -> bool:
246255
if self.current_uid == "":
247256
return False
248-
return False
257+
working_platform: Instance | None = self.platforms.get(self.current_uid, None)
258+
if working_platform is None:
259+
return ""
260+
return working_platform.deployed
249261

250262
# === end of platform detail vars ===
251263

@@ -368,7 +380,12 @@ def instance_uncaught(self) -> bool:
368380

369381
@rx.var
370382
def instance_deployable(self) -> bool:
371-
return True
383+
if self.current_uid == "":
384+
return False
385+
working_platform: Instance | None = self.platforms.get(self.current_uid, None)
386+
if working_platform is None:
387+
return False
388+
return self.check_instance_deployable(working_platform)
372389
# === end of instance validation bars ===
373390

374391
# Events
@@ -545,6 +562,11 @@ def toggle_federation(self):
545562
working_platform: Instance = self.platforms[self.current_uid]
546563
working_platform.federation_checked = not working_platform.federation_checked
547564

565+
@rx.event
566+
def update_password_field(self, value: str):
567+
working_platform_instance = self.platforms[self.current_uid]
568+
working_platform_instance.password = value
569+
548570
@rx.event
549571
def update_detail(self, field: str, value):
550572
working_platform_instance = self.platforms[self.current_uid]
@@ -565,13 +587,15 @@ def update_platform_config_detail(self, field: str, value: str):
565587
@rx.event
566588
async def handle_deploy(self):
567589
working_platform: Instance = self.platforms[self.current_uid]
568-
569-
if working_platform.uncaught != False and working_platform.valid:
570-
working_platform.safe_host_entry = working_platform.host.to_dict()
571-
working_platform.uncaught = False
572-
await deploy_platform(working_platform.platform.config.instance_name)
590+
try:
591+
response = await deploy_platform(working_platform.platform.config.instance_name, working_platform.password)
592+
working_platform.deployed = True
593+
logger.debug(f"response: {response.json()}")
573594
yield rx.toast.success("Deployed Successfully!")
574-
595+
except Exception as e:
596+
logger.debug(f"there was an error deploying platform {working_platform.platform.config.instance_name}. e: {e}")
597+
yield rx.toast.error(f"There was an error deploying platform: {working_platform.platform.config.instance_name}")
598+
575599
@rx.event
576600
async def handle_save(self):
577601
working_platform: Instance = self.platforms[self.current_uid]
@@ -730,6 +754,9 @@ def check_instance_savable(self, working_platform: Instance) -> bool:
730754

731755
return savable
732756

757+
def check_instance_deployable(self, working_platform: Instance) -> bool:
758+
return True if self.check_instance_uncaught(working_platform) == False and working_platform.new_instance == False else False
759+
733760
def connection_validity(self, working_platform: Instance) -> tuple[bool, dict[str, bool]]:
734761
valid = True
735762
validity_map: dict[str, bool] = {

volttron_installer/thin_endpoint_wrappers/__init__.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import httpx, asyncio
2-
from typing import Any, Optional, TypeVar, Type, Union, List, Dict
2+
from typing import Any, Literal, Optional, TypeVar, Type, Union, List, Dict
33

44
from ..backend.models import AgentType, HostEntry, PlatformDefinition, \
55
CreatePlatformRequest, CreateOrUpdateHostEntryRequest, ReachableResponse, \
@@ -109,6 +109,24 @@ async def delete_request(url: str, params: Optional[dict[str, Any]] = None,
109109
except Exception as e:
110110
raise ApiError(500, str(e))
111111

112+
async def request(url: str, method: Literal["POST", "GET", "PUT"] ="", timeout: float = DEFAULT_TIMEOUT, **kwargs) -> httpx.Response:
113+
"""Send an async POST request to the specified URL with optional JSON data."""
114+
async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
115+
try:
116+
response = await client.request(
117+
method=method,
118+
url=url,
119+
**kwargs
120+
)
121+
response.raise_for_status()
122+
return response
123+
except httpx.TimeoutException:
124+
raise ApiError(408, f"Request timed out connecting to {url}")
125+
except httpx.HTTPStatusError as e:
126+
raise ApiError(e.response.status_code, e.response.text)
127+
except Exception as e:
128+
raise ApiError(500, str(e))
129+
112130
# Endpoints.
113131
# GET requests
114132
@with_model(HostEntry)
@@ -159,8 +177,8 @@ async def update_agent(platform_id: str, agent_id: str, agent: CreateAgentReques
159177
async def create_platform(platform: CreatePlatformRequest):
160178
await post_request(f"{API_BASE_URL}{PLATFORMS_PREFIX}/", data=platform.model_dump())
161179

162-
async def deploy_platform(platform_id: str):
163-
await post_request(f"{API_BASE_URL}{PLATFORMS_PREFIX}/deploy/{platform_id}")
180+
async def deploy_platform(platform_id: str, password: str):
181+
return await request(f"{API_BASE_URL}{PLATFORMS_PREFIX}/deploy/{platform_id}", "POST", params={"password":password})
164182

165183
async def add_host(host: CreateOrUpdateHostEntryRequest):
166184
await post_request(f"{API_BASE_URL}{HOSTS_PREFIX}", data=host.model_dump())

0 commit comments

Comments
 (0)