|
| 1 | +# Workflow report |
| 2 | + |
| 3 | +## Introduction |
| 4 | +Every installer command is internally based on the [assets framework][../design/assetgeneration.md], which allows to define a directed acyclic graph of assets (a generic work item). |
| 5 | +A workflow identifies a set of asset graph paths executed when running a specific command (note that the same asset may behave differently when triggered under different workflows). |
| 6 | + |
| 7 | +A report allows to collect the main relevant workflow events - as well as any eventual error, and detailed results - in a human-readable format, providing an abstraction from the basic asset logging system. |
| 8 | +A report also serializes immediately on the disk any update received, thus providing a simple mechanism to support streaming the progression of the current command execution (particulary |
| 9 | +useful in case of remote execution). |
| 10 | + |
| 11 | +## Stages |
| 12 | +A report is a composed by a number of sequential _stage_. A stage represents a specific workflow phase (given by one or more assets) that could be relevant and/or informative from the user point of view. |
| 13 | +A stage is composed by a _stage identifier_ (or briefly, a stage id) and a number of substages: |
| 14 | + |
| 15 | +* The stage id is defined by a short internal identifier and a longer human-readable description, meant to be shown to the user. |
| 16 | +* Substages are a sequential of zero or more stages, and they are meant to provide a further level of details for the owner stage, if required. |
| 17 | + |
| 18 | +### Stages ids |
| 19 | +A stage id can be defined via the `NewStageID` method, for example: |
| 20 | +``` |
| 21 | +StageFetchBaseISO wr.StageID = wr.NewStageID("fetch-base-iso", "Retrieving the base ISO image") |
| 22 | +``` |
| 23 | + |
| 24 | +A substage id can be defined by prefixing the internal id with the owner stage id, in the format `<owner stage>.<substage>`, for example: |
| 25 | +``` |
| 26 | +StageFetchBaseISOExtract wr.StageID = wr.NewStageID("fetch-base-iso.extract-image", "Extracting base image from release payload") |
| 27 | +StageFetchBaseISOVerify wr.StageID = wr.NewStageID("fetch-base-iso.verify-version", "Verifying base image version") |
| 28 | +StageFetchBaseISODownload wr.StageID = wr.NewStageID("fetch-base-iso.download-image", "Downloading base ISO image") |
| 29 | +``` |
| 30 | + |
| 31 | +### Substages |
| 32 | +Substages are completely optional, and they may be useful for detailing a particularly big or lengthy stage. So, it's perfectly fine to define stages without any substage. |
| 33 | +The current framework does not support more than two levels of stages, essentially for keeping both a simpler interface and for producing an easy to read output for the |
| 34 | +final user. |
| 35 | + |
| 36 | +### (Sub)Stage result |
| 37 | +The workflow report framework allows to attach (optionally) an artifact for each stage (or substage), in order to capture the end result of the stage execution. The result field is |
| 38 | +a free-text string, and its format depends on the specific stage (even though a JSON format is recommended). |
| 39 | + |
| 40 | +## Populating a report |
| 41 | +Every asset can access the current report from the `Generate()` context object (for the installer commands where the reporting have been enabled), using the `GetReport()` method. |
| 42 | +Once retrieved, the report `Stage` method can be used to add a new stage to the current report: |
| 43 | +``` |
| 44 | +workflowreport.GetReport(ctx).Stage(workflow.StageFetchBaseISO) |
| 45 | +``` |
| 46 | + |
| 47 | +A similar approach could be follow to add a new substage to the report: |
| 48 | +``` |
| 49 | +workflowreport.GetReport(ctx).SubStage(workflow.StageFetchBaseISOExtract) |
| 50 | +``` |
| 51 | + |
| 52 | +_Note: a substage cannot be added before adding the related owner stage._ |
| 53 | + |
| 54 | +## Enabling the report for a command |
| 55 | +If a report was not previously enabled for a specific command, the previously shown commands will have no effect. To active the reporting, |
| 56 | +it is sufficient to use the `workflowreport.Context()` method which will create a dedicated context to be used in the assets generation: |
| 57 | + |
| 58 | +``` |
| 59 | +func NewAddNodesCommand(directory string, kubeConfig string) error { |
| 60 | + |
| 61 | + ctx := workflowreport.Context(string(workflow.AgentWorkflowTypeAddNodes), directory) |
| 62 | +
|
| 63 | + fetcher := store.NewAssetsFetcher(directory) |
| 64 | + err = fetcher.FetchAndPersist(ctx, ...) // |
| 65 | +
|
| 66 | + workflowreport.GetReport(ctx).Complete(err) |
| 67 | +``` |
| 68 | + |
| 69 | +At the end, the `Complete(err)` method must be invoked to close the report (and eventually report any error). |
| 70 | + |
| 71 | +## Appendix |
| 72 | + |
| 73 | +### Sample of report.json file (without any result) |
| 74 | +``` |
| 75 | +{ |
| 76 | + "id": "report-addnodes-202410301546", |
| 77 | + "start_time": "2024-10-30T15:46:36.646915757Z", |
| 78 | + "end_time": "2024-10-30T15:47:23.689529009Z", |
| 79 | + "stages": [ |
| 80 | + { |
| 81 | + "id": "add-nodes-cluster-inspection", |
| 82 | + "description": "Gathering additional information from the target cluster", |
| 83 | + "start_time": "2024-10-30T15:46:36.646915757Z", |
| 84 | + "end_time": "2024-10-30T15:46:36.814616705Z" |
| 85 | + }, |
| 86 | + { |
| 87 | + "id": "create-manifest", |
| 88 | + "description": "Creating internal configuration manifests", |
| 89 | + "start_time": "2024-10-30T15:46:36.8146174Z", |
| 90 | + "end_time": "2024-10-30T15:46:37.890492356Z" |
| 91 | + }, |
| 92 | + { |
| 93 | + "id": "ignition", |
| 94 | + "description": "Rendering ISO ignition", |
| 95 | + "start_time": "2024-10-30T15:46:37.890493244Z", |
| 96 | + "end_time": "2024-10-30T15:46:38.227771699Z" |
| 97 | + }, |
| 98 | + { |
| 99 | + "id": "fetch-base-iso", |
| 100 | + "description": "Retrieving the base ISO image", |
| 101 | + "start_time": "2024-10-30T15:46:38.227772149Z", |
| 102 | + "end_time": "2024-10-30T15:47:00.63994573Z", |
| 103 | + "sub_stages": [ |
| 104 | + { |
| 105 | + "id": "fetch-base-iso.extract-image", |
| 106 | + "description": "Extracting base image from release payload", |
| 107 | + "start_time": "2024-10-30T15:46:38.228032465Z", |
| 108 | + "end_time": "2024-10-30T15:46:51.428272041Z" |
| 109 | + }, |
| 110 | + { |
| 111 | + "id": "fetch-base-iso.verify-version", |
| 112 | + "description": "Verifying base image version", |
| 113 | + "start_time": "2024-10-30T15:46:51.428273074Z", |
| 114 | + "end_time": "2024-10-30T15:47:00.639945356Z" |
| 115 | + } |
| 116 | + ] |
| 117 | + }, |
| 118 | + { |
| 119 | + "id": "create-agent-artifacts", |
| 120 | + "description": "Creating agent artifacts for the final image", |
| 121 | + "start_time": "2024-10-30T15:47:00.639946343Z", |
| 122 | + "end_time": "2024-10-30T15:47:20.70873527Z", |
| 123 | + "sub_stages": [ |
| 124 | + { |
| 125 | + "id": "create-agent-artifacts.agent-tui", |
| 126 | + "description": "Extracting required artifacts from release payload", |
| 127 | + "start_time": "2024-10-30T15:47:00.641937138Z", |
| 128 | + "end_time": "2024-10-30T15:47:10.419651275Z" |
| 129 | + }, |
| 130 | + { |
| 131 | + "id": "create-agent-artifacts.prepare", |
| 132 | + "description": "Preparing artifacts", |
| 133 | + "start_time": "2024-10-30T15:47:10.419652528Z", |
| 134 | + "end_time": "2024-10-30T15:47:20.708735111Z" |
| 135 | + } |
| 136 | + ] |
| 137 | + }, |
| 138 | + { |
| 139 | + "id": "generate-iso", |
| 140 | + "description": "Assembling ISO image", |
| 141 | + "start_time": "2024-10-30T15:47:20.708735596Z", |
| 142 | + "end_time": "2024-10-30T15:47:23.689529009Z" |
| 143 | + } |
| 144 | + ], |
| 145 | + "result": { |
| 146 | + "exit_code": 0 |
| 147 | + } |
| 148 | +} |
| 149 | +``` |
0 commit comments