Changes for README.md: 152 added lines, 18 removed lines.
Original line number
Diff line number
Diff line
# Generic Controller example
OSL's Service orchestrator (OSOM) has the capability of contacting external controllers, given a specific resource category that this controller can manage.
OpenSlice's service orchestrator (**OSOM**) can delegate the lifecycle of a resource to an external
controller, given the resource **category** that controller declares it manages. This project is a
worked example of such a controller: it registers a catalogue of Resource Specifications, handles
create/update/delete requests for them, and — importantly — supports OSOM's **planning / simulation**
dry-runs, reporting back a simulated cost for each lifecycle phase.
This project is an example of creating a generic controller, that registers two Resource Specifications for managing resources ResourceA and ResourceB.
Everything here is illustrative. The "logic" invents plausible-looking status values and provisions
nothing; the cost figures are made up. What is real, and what is worth copying, is the *shape*: the
queue conventions, the simulation contract, and the estimate contract.
Listens for messages on queues as registered by category name and version for CREATE/UPD/DELETE, with this scheme:
> the full architecture and authoring guide, including the rules that fail silently if you get them
> wrong. This README is the quick tour.
- CREATE / category_name / version
- UPDATE / category_name / version
- DELETE / category_name / version
---
here we have:
## Running it
- category: gcontroller.examples.osl.etsi.org
- version: 0.1.0
```bash
mvn spring-boot:run
```
Point `spring.activemq.brokerUrl` in `src/main/resources/application.yml` at OpenSlice's Artemis broker
first. On startup you should see one `Registering resource specification: ...` line per spec; they then
appear in OpenSlice's resource catalogue, ready to be referenced from a service specification.
The project registers automatically the two Resource Specifications (RSpecs) and we added handler functions for create, update and delete.
```bash
mvn test# 67 tests, no broker or OpenSlice instance required
```
So when you create CFSs services using these (RSpecs) the Service Orchestrator will call these functions via the queue
## Category and version
See BootstrapService that registers the two RSpecs as LogicalResourceSpecifications
```yaml
osl-controller:
category:gcontroller.examples.osl.etsi.org
version:0.1.0
```
The two classes has function to transform to TMF RSpecs, as well as to save back to OpenSlice their Resource Instances (thus they will go to the inventory)
These two strings are the whole binding between OSOM and the controller — they name the queues and they
are the category the specs register under. Change them and you have a different controller.
The ResourceRepoService class has method calls for the handling of the messages from the orchestrator.
## Queues
Useful metadata are included in some headers of the message:
The controller listens on `<VERB>/<category>/<version>`, plus a `/PLANNING` variant of each:
- important header org.etsi.osl.resourceId is the UUID of the related resource that was created in OpenSlice and reflects the resource that this controller will handle. NOTE: you need to UPDATE this resource back in TMFAPI and set the status at least ResourceStatusType.AVAILABLE or TERMINATED if there are errors, etc
- header org.etsi.osl.serviceOrderId is the UUID of the related service order
- header org.etsi.osl.serviceId is the UUID of the related services
| Queue | Purpose |
|---|---|
| `CREATE/gcontroller.examples.osl.etsi.org/0.1.0` | Real deployment |
Changes for docs/index.md: 1 added line, 0 removed lines.
Original line number
Diff line number
Diff line
@@ -2,6 +2,7 @@
| Doc | Description |
|---|---|
| [20260719_0017_writing-an-openslice-controller.md](20260719_0017_writing-an-openslice-controller.md) | **Start here to write your own controller.** Architecture and authoring guide: what a generic controller is and why the category is the whole contract; the component map and the one-registry-not-four-lists decision; both request paths end to end (production writes vs planning callbacks) with sequence diagrams; the simulation contract — run the real logic, suppress side effects, model deployment as taking time, target the id OSOM acknowledged; the estimate contract including the null-is-not-zero rule and the duty-cycled operation phase; a step-by-step walkthrough for building your own; and the gotchas that fail silently (spec names as a JMS join key, `specType()` only honoured on first registration, lenient catalog reply parsing, singleton specs and concurrency, `Math.abs` on a hash). Also rewrites the stale README, which still described the original two-spec state. |
| [20260718_2236_duty-cycle-engineer-operation-estimate.md](20260718_2236_duty-cycle-engineer-operation-estimate.md) | Bill `RadioEngineer` for hours *worked* rather than hours elapsed. A 30-day engagement charged `720 h x €45` as if the engineer were on duty around the clock; `ResourceEstimator.Profile` gains an `operationHoursPerDay` duty cycle (defaulting to 24 via a secondary constructor, so no other spec's figures move) and the same engagement now costs `30 x 8 x €45`. The reported `durationSeconds` deliberately keeps echoing OSOM's window — only energy and cost are duty-cycled. The requested `shiftHours` reaches the estimate through a new overridable `estimateProfile(ResourceUpdate)` rather than the singleton's mutable field, which the background OPERATION callback would have raced on. |
| [20260716_1615_more-example-resource-specs.md](20260716_1615_more-example-resource-specs.md) | Grow the demo catalogue from 2 specs to 10 — `VirtualMachine`, `VPNAccess`, `KubernetesCluster`, `5GCore`, `RadioNode`, `CPE`, `MobilePhone`, `RadioEngineer` — each with its own characteristics and (invented) estimate profile spanning three orders of magnitude. The four tangible ones register as `PhysicalResourceSpecification`; `RadioEngineer` reports measured-zero energy against a labour cost rate, exercising the estimate contract's null-is-not-zero rule. Replaces the four hard-coded lists that had to stay in sync with one `ExampleResourceSpec` base plus a fail-fast `ResourceSpecRegistry`, so adding a spec is one class and one line. Fixes `CatalogClient` reply strictness (physical specs would have stack-traced at every startup) and a `Math.abs(hash)` idiom that can go negative. Adds the project's first tests (58). |
| [20260716_1430_report-lifecycle-estimates.md](20260716_1430_report-lifecycle-estimates.md) | Report simulated CREATION / OPERATION / TEARDOWN estimates (seconds / Watt-hours / dimensionless units) back to OSOM as JMS headers on the planning callback, one phase per callback. New stateless `ResourceEstimator` holds the per-spec cost model (invented numbers — it demonstrates the contract, it models nothing real); the OPERATION phase is sized by the `org.etsi.osl.operationDurationSeconds` window OSOM sends, and is omitted entirely when that header is absent rather than defaulted locally. Also adds `UPDATE/…/PLANNING` and `DELETE/…/PLANNING` routes, so OSOM's day-2 dry-runs stop landing on the production queues — `UNDER SIMULATION DELETE` now actually appears in the log. |