From 21c6fcb275ab57d10b053db33c09a38dc78a2c3d Mon Sep 17 00:00:00 2001 From: Joao Eduardo Luis Date: Tue, 15 Jun 2021 06:12:06 +0000 Subject: [PATCH 1/3] gravel: setting hostname must update state We need to update the in-memory state for the node setting a new hostname; otherwise we will be joining or creating a new cluster with, potentially, the old hostname. Signed-off-by: Joao Eduardo Luis --- ...stall-create-wizard-page.component.spec.ts | 2 +- .../install-create-wizard-page.component.ts | 4 +--- .../install-join-wizard-page.component.ts | 4 +--- .../app/shared/services/api/nodes.service.ts | 12 +++++++++++ .../app/shared/services/api/orch.service.ts | 11 ---------- src/gravel/api/nodes.py | 18 ++++++++++++++++ src/gravel/api/orch.py | 21 +------------------ .../{orch/system.py => nodes/host.py} | 0 src/gravel/controllers/nodes/mgr.py | 14 +++++++++++++ 9 files changed, 48 insertions(+), 38 deletions(-) rename src/gravel/controllers/{orch/system.py => nodes/host.py} (100%) diff --git a/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.spec.ts b/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.spec.ts index b0c3d9bf0..cdf959233 100644 --- a/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.spec.ts +++ b/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.spec.ts @@ -69,7 +69,7 @@ describe('InstallCreateWizardPageComponent', () => { it('should show notification only once [3]', fakeAsync(() => { component.startBootstrap(); httpTesting - .match({ url: 'api/orch/hostname', method: 'PUT' })[0] + .match({ url: 'api/nodes/hostname', method: 'PUT' })[0] .error(new ErrorEvent('Unknown error'), { status: 500 }); tick(5); expect(toastrService.error).toHaveBeenCalledTimes(1); diff --git a/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.ts b/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.ts index bcc4243c3..ca2077ad9 100644 --- a/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.ts +++ b/src/glass/src/app/pages/install-wizard/install-create-wizard-page/install-create-wizard-page.component.ts @@ -30,7 +30,6 @@ import { NodesService, NodeStageEnum } from '~/app/shared/services/api/nodes.service'; -import { OrchService } from '~/app/shared/services/api/orch.service'; import { NotificationService } from '~/app/shared/services/notification.service'; import { PollService } from '~/app/shared/services/poll.service'; @@ -69,7 +68,6 @@ export class InstallCreateWizardPageComponent implements OnInit { private localNodeService: LocalNodeService, private nodesService: NodesService, private notificationService: NotificationService, - private orchService: OrchService, private pollService: PollService ) {} @@ -150,7 +148,7 @@ export class InstallCreateWizardPageComponent implements OnInit { * This step starts the bootstrap process */ startBootstrap(): void { - this.orchService.setHostname(this.context.config.hostname).subscribe({ + this.nodesService.setHostname(this.context.config.hostname).subscribe({ complete: () => { this.blockUI.start(translate(TEXT('Please wait, checking node status ...'))); this.pollNodeStatus(); diff --git a/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts b/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts index 6e7fe7942..5268a3b00 100644 --- a/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts +++ b/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts @@ -27,7 +27,6 @@ import { StatusStageEnum } from '~/app/shared/services/api/local.service'; import { NodesService } from '~/app/shared/services/api/nodes.service'; -import { OrchService } from '~/app/shared/services/api/orch.service'; import { NotificationService } from '~/app/shared/services/notification.service'; import { PollService } from '~/app/shared/services/poll.service'; @@ -64,7 +63,6 @@ export class InstallJoinWizardPageComponent implements OnInit { private localNodeService: LocalNodeService, private nodesService: NodesService, private notificationService: NotificationService, - private orchService: OrchService, private pollService: PollService ) {} @@ -122,7 +120,7 @@ export class InstallJoinWizardPageComponent implements OnInit { this.context.stepperVisible = false; this.blockUI.start(translate(TEXT('Please wait, start joining existing cluster ...'))); concat( - this.orchService.setHostname(this.context.config.hostname), + this.nodesService.setHostname(this.context.config.hostname), this.nodesService.join({ address: `${this.context.config.address}:${this.context.config.port}`, token: this.context.config.token diff --git a/src/glass/src/app/shared/services/api/nodes.service.ts b/src/glass/src/app/shared/services/api/nodes.service.ts index 403c3b759..7f2e40ad0 100644 --- a/src/glass/src/app/shared/services/api/nodes.service.ts +++ b/src/glass/src/app/shared/services/api/nodes.service.ts @@ -66,6 +66,10 @@ export type DiskSolution = { possible: boolean; }; +export type SetHostnameRequest = { + name: string; +}; + @Injectable({ providedIn: 'root' }) @@ -116,4 +120,12 @@ export class NodesService { deploymentDiskSolution(): Observable { return this.http.get(`${this.deploymentURL}/disksolution`); } + + /** + * Setup hostname + */ + setHostname(name: string): Observable { + const request: SetHostnameRequest = { name }; + return this.http.put(`${this.url}/hostname`, request); + } } diff --git a/src/glass/src/app/shared/services/api/orch.service.ts b/src/glass/src/app/shared/services/api/orch.service.ts index 3697ccab5..dcc99fdad 100644 --- a/src/glass/src/app/shared/services/api/orch.service.ts +++ b/src/glass/src/app/shared/services/api/orch.service.ts @@ -39,10 +39,6 @@ export type HostDevices = { devices: Device[]; }; -export type SetHostnameRequest = { - name: string; -}; - @Injectable({ providedIn: 'root' }) @@ -65,11 +61,4 @@ export class OrchService { return this.http.get<{ [hostName: string]: HostDevices }>(`${this.url}/devices`); } - /** - * Setup hostname - */ - setHostname(name: string): Observable { - const request: SetHostnameRequest = { name }; - return this.http.put(`${this.url}/hostname`, request); - } } diff --git a/src/gravel/api/nodes.py b/src/gravel/api/nodes.py index ce65649ee..24110ba7f 100644 --- a/src/gravel/api/nodes.py +++ b/src/gravel/api/nodes.py @@ -81,6 +81,10 @@ class StartDeploymentRequest(BaseModel): ntpaddr: str = Field(title="NTP server address") +class SetHostnameRequest(BaseModel): + name: str = Field(min_length=1, title="The system hostname") + + @router.get("/deployment/disksolution", response_model=DiskSolution) async def node_get_disk_solution(request: Request) -> DiskSolution: """ @@ -217,6 +221,20 @@ async def nodes_get_token(request: Request): ) +@router.put("/hostname", response_model=bool) +async def put_hostname(request: Request, req: SetHostnameRequest) -> bool: + nodemgr: NodeMgr = request.app.state.nodemgr + if nodemgr.deployment_state.deployed or nodemgr.deployment_state.ready: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Node already deployed") + try: + await nodemgr.set_hostname(req.name) + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=str(e)) + return True + + router.add_websocket_route( # pyright: reportUnknownMemberType=false "/nodes/ws", IncomingConnection diff --git a/src/gravel/api/orch.py b/src/gravel/api/orch.py index 7d9ed273c..cad49c90d 100644 --- a/src/gravel/api/orch.py +++ b/src/gravel/api/orch.py @@ -15,12 +15,10 @@ from fastapi.routing import APIRouter from fastapi.logger import logger as fastapi_logger from fastapi import HTTPException, status, Request -from pydantic import BaseModel, Field +from pydantic import BaseModel from typing import Dict, List -from gravel.controllers.nodes.mgr import NodeMgr from gravel.controllers.orch.models import OrchDevicesPerHostModel -from gravel.controllers.orch.system import set_hostname from gravel.controllers.orch.orchestrator \ import Orchestrator @@ -55,10 +53,6 @@ class HostsDevicesModel(BaseModel): devices: List[DeviceModel] -class SetHostnameRequest(BaseModel): - name: str = Field(min_length=1, title="The system hostname") - - class SetNtpRequest(BaseModel): addr: str @@ -136,16 +130,3 @@ async def get_pubkey(request: Request) -> str: except Exception as e: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e)) - - -@router.put("/hostname", response_model=bool) -async def put_hostname(request: Request, req: SetHostnameRequest) -> bool: - nodemgr: NodeMgr = request.app.state.nodemgr - if nodemgr.deployment_state.deployed or nodemgr.deployment_state.ready: - raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Node already deployed") - try: - return set_hostname(req.name) - except Exception as e: - raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=str(e)) diff --git a/src/gravel/controllers/orch/system.py b/src/gravel/controllers/nodes/host.py similarity index 100% rename from src/gravel/controllers/orch/system.py rename to src/gravel/controllers/nodes/host.py diff --git a/src/gravel/controllers/nodes/mgr.py b/src/gravel/controllers/nodes/mgr.py index e54d7dd01..e63590865 100644 --- a/src/gravel/controllers/nodes/mgr.py +++ b/src/gravel/controllers/nodes/mgr.py @@ -35,6 +35,7 @@ DeploymentState, NodeDeployment ) +from gravel.controllers.nodes.host import HostnameCtlError, set_hostname from gravel.controllers.orch.ceph import ( CephCommandError, Mon @@ -307,6 +308,19 @@ def gen() -> str: tokenstr = '-'.join(gen() for _ in range(4)) return tokenstr + async def set_hostname(self, name: str) -> None: + logger.info(f"set hostname '{name}'") + try: + set_hostname(name) + except HostnameCtlError as e: + logger.error(f"set hostname: {e.message}") + raise e + except Exception as e: + logger.error(f"set hostname: {str(e)}") + raise NodeError(f"setting hostname: {str(e)}") + self._state.hostname = name + await self._save_state() + async def join(self, leader_address: str, token: str) -> bool: logger.debug( f"join > with leader {leader_address}, token: {token}" From 2034a7fda4e8c11defd43e45d7b23683e6ec33de Mon Sep 17 00:00:00 2001 From: Joao Eduardo Luis Date: Tue, 15 Jun 2021 06:14:29 +0000 Subject: [PATCH 2/3] gravel: orch: drop artifact Signed-off-by: Joao Eduardo Luis --- src/gravel/api/orch.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/gravel/api/orch.py b/src/gravel/api/orch.py index cad49c90d..e7bdf85e9 100644 --- a/src/gravel/api/orch.py +++ b/src/gravel/api/orch.py @@ -53,10 +53,6 @@ class HostsDevicesModel(BaseModel): devices: List[DeviceModel] -class SetNtpRequest(BaseModel): - addr: str - - @router.get("/hosts", response_model=List[HostModel]) def get_hosts(request: Request) -> List[HostModel]: orch = Orchestrator(request.app.state.gstate.ceph_mgr) From b4141a3625aaade4762ec43deadb3a4856a875c0 Mon Sep 17 00:00:00 2001 From: Joao Eduardo Luis Date: Tue, 15 Jun 2021 07:19:17 +0000 Subject: [PATCH 3/3] glass: fix join step transition on success Signed-off-by: Joao Eduardo Luis --- .../install-join-wizard-page.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts b/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts index 5268a3b00..09ac11102 100644 --- a/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts +++ b/src/glass/src/app/pages/install-wizard/install-join-wizard-page/install-join-wizard-page.component.ts @@ -163,10 +163,12 @@ export class InstallJoinWizardPageComponent implements OnInit { switch (res.node_stage) { case StatusStageEnum.none: case StatusStageEnum.unknown: + this.context.stage = 'unknown'; this.handleError(TEXT('Failed to join existing cluster.')); break; case StatusStageEnum.ready: - this.context.stage = 'unknown'; + this.context.stage = 'joined'; + this.context.stepperVisible = true; this.blockUI.stop(); this.stepper?.next(); break;