Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

agent deployment doc updates #294

Merged
merged 2 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions docs/symphony-book/agent/_overview.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
# Symphony agents

_(last edit: 3/14/2024)_
_(last edit: 6/4/2024)_

Symphony doesn’t mandate an agent to be installed on the targets it manages. Symphony prefers remote management interfaces when possible. On the other hand, if a target doesn’t support a remote management interface, a Symphony agent can be installed on the target so that Symphony control plane can manage it.

Symphony has four types of agentsSymphony target agent, Symphony proxy agent, Symphony poll agent, and a lightweight Symphony poll agent (code name Piccolo), as summarized in the following table:
Symphony has four types of agents: Symphony agent, Symphony target agent, Symphony poll agent, and a lightweight Symphony poll agent (code name Piccolo), as summarized in the following table:

| Agent Type | Protocol |
|--------|--------|
| Lightweight poll agent | HTTPS (outbound) |
| Poll agent | HTTPS (outbound) |
| Proxy agent | MQTT or HTTPS (inbound) |
| Target agent | HTTPS (outbound) |
| Agent Type | Protocol | Summary |
|--------|--------|--------|
| Lightweight poll agent | HTTPS (outbound) | Polls and applies target desired state |
| Poll agent | HTTPS (outbound) | Polls and applies target desired state |
| Target agent | MQTT or HTTPS (inbound) | Control plane pushes desired state |
| Symphony agent | N/A | Runs on a target to provide additional functionalities<sup>1</sup> |

> **NOTE:** Except for Piccolo, you can also combine agents into a combined agent, such has a Poll agent + Target agent.
<sup>1</sup>: The Symphony agent provides additional features to a target, such as the ability to take camera snapshots. This agent has nothing to do with the [state seeking](../concepts/state_seeking.md) process, nor the different deployment topologies.

## Related topics
> **NOTE:** Except for Piccolo, you can also combine agents into a combined agent, such as a Poll agent + Target agent.

## Symphony Deployment Topologies

Symphony supports several different deployment topologies to accommodate different requirements, as summarized by the following diagram.

* [Symphony lightweight polling agent (Piccolo)](./polling-agent.md)
* [Symphony polling agent](./polling-agent.md)
* [Symphony target agent](./target-agent.md)
![deployment-topologies](../images/deployment-topologies.png)

### In-proc providers (without separate agents)
By default, all Symphony target providers are loaded into the Symphony API process. This means that all providers are invoked through direct in-process calls. The provider in turn uses APIs from corresponding toolchains to interact with the underlying systems. For example, when a Kubernetes target provider is used, the provider is invoked in-process in the Symphony API process and uses a Kubernetes client to interact with the Kubernetes API server (either on the same cluster or on a different cluster).
### Proxy providers (with target agents)
In some cases, you may want to run the target providers in a separate process. For example, when you need to manage a target on a different network, you may want to use a proxy provider to interact with the remote target. In this case, targe providers will be loaded and executed on a separate Symphony agent.
Symphony control plane communicates with these Symphony agents through either HTTP or MQTT. In the case of HTTP, the Symphony agent needs to host a Web server that exposes the expected HTTP endpoints; in the case of MQTT, the Symphony agent and the Symphony control plane are connected to a shared MQTT broker.
Running target providers in a separate agent has several advantages:
1. Fine-granular access control. Instead of granting Symphony API with access to all managed systems, you can isolate different systems into separate Symphony agents and assign minimum required accesses.
2. If needed, you can implement your own agent from the ground up with any programming language of your choice. Or you can use the default Symphony agent implementation that supports both HTTP and MQTT protocol. A custom agent implementation can be used in scenarios where you need specific programming languages (such as certified Rust versions) or implementations.
3. Support different network topologies. For example, if you manage a remote target that can’t be directly reached, you can use a MQTT proxy to bridge connection between the control plane and the target through outbound connections.
### Poll-based agents
The proxy providers above use a “push” mode, in which the desired state is pushed to the target agents. In cases where inbound connections are impossible, you can use poll-based agents that communicate with the control plane through a single outbound connection. These agents periodically poll the control plane for the new desired state and apply the state to local targets.
Symphony provides two poll-based agents: a full-scale agent that supports all Symphony target provider types, and a light-weight agent (Piccolo) that supports deploying Web Assemblies and eBPF modules only. The light-weight agent is less than 4MB in size, so it’s suitable for tiny devices.
### Multi-site deployment
You can link multiple Symphony control planes together into a cascaded control plane tree. Please see [multi-site](../multi-site/_overview.md) for more details on multi-site deployments.

## Related topics

* [Target agent](./target-agent.md)
* [Polling agent](./polling-agent.md)
* [Lightweight polling agent (Piccolo)](./piccolo-agent.md)
* [Symphony agent](./symphony-agent.md)
96 changes: 94 additions & 2 deletions docs/symphony-book/agent/polling-agent.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,102 @@
# Symphony polling agent
# Polling agent

_(last edit: 3/14/2024)_
_(last edit: 6/4/2024)_

Symphony polling agent connects to the Symphony control plane through a single outbound HTTPS connection. It reports target current states and retrieves the new desired states from the control plane. Then, it runs a local reconciliation process. The polling agent is used in conjunction with Staging Target provider, which stages the desired state on the control plane itself instead of pushing it out to the target. The polling agent periodically polls the control plane for updated desired states.

![polling-agent](../images/polling-agent.png)

## Workflow to configure a polling agent
1. Configure and launch a polling agent process. A polling agent can run as a single process, a Docker container, or a Kubernetes service (while running on a Kubernetes cluster). The polling agent uses the same binary that is used by Symphony API. It’s just loaded with a different configuration file that puts itself into the agent mode.
2. Define your target definition. The target should use a staged provider (either `providers.target.stage`. This provider writes the target desired state to a `Catalog` object, which can be then queried by a polling agent through Symphony API.
3. Define your solutions and instances as usual. When the solution is deployed to the target, Symphony realizes that the desired state of the components needs to be staged on the control plane itself as a `Catalog` object. Once the object is written, it can be queried by a polling agent through the Symphony API.

## Polling agent configuration file

> **NOTE:** You can see a sample polling agent configuration file at [api/symphony-api-poll-agent.json](../../../api/symphony-k8s-poll-agent.json)

The core target agent functionality is delivered by the `vendors.solution` vendor (a vendor is a microservice in Symphony's architecture).
```json
{
"type": "vendors.solution",
"loopInterval": 15,
"route": "solution",
"managers": [
{
"name": "solution-manager",
"type": "managers.symphony.solution",
"properties": {
...
"isTarget": "true",
"targetNames": "test-target",
"poll.enabled": "true"
},
"providers": {
...
"helm.v3": {
"type": "providers.target.helm",
"config": {
"inCluster": true
}
},
"yaml.k8s": {
"type": "providers.target.kubectl",
"config": {
"inCluster": true
}
},
"instance": {
"type": "providers.target.k8s",
"config": {
"inCluster": true,
"deploymentStrategy": "services"
}
},
"configmap": {
"type": "providers.target.configmap",
"config": {
"inCluster": true
}
},
"ingress": {
"type": "providers.target.ingress",
"config": {
"inCluster": true
}
}
}
}
]
}
```
The vendor loads a `managers.symphony.solution` (a manager is a reusable business logic unit in Symphony's architecture), which defines how the agent represents on or more Symphony targets.

* **isTarget**: This is the flag that puts the process into the target agent mode. Like mentioned earlier, target agent is the same binary as what's used by the Symphony API. This flag puts the process into agent mode.
* **targetNames"**: This is a comma-separate list that lists out Symphony target names the agent represents. An agent can represent one or more Symphony targets. **The names listed here must match with target names defined on the Symphony control plane.**
* **poll.enabled**: This is the attribute that enables the polling agent.
* Provider definitions. These provider definitions maps component types to target providers. For example, in the above configuration, the `rtos` component type is mapped to a `providers.target.script` provider.

> **NOTE**: You don't need to define any protocol bindings as you do for the [target agent](target-agent.md), because the polling agent always uses HTTPS.

## Target definition
Your target definition needs to use a `providers.target.staging` to stage the target desired state on the control plane as a `Catalog` object, named as `<target-name>-state`. For example:

```yaml
apiVersion: fabric.symphony/v1
kind: Target
metadata:
name: sample-staged-k8s
spec:
topologies:
- bindings:
- role: instance
provider: providers.target.staging
config:
targetName: "sample-staged-k8s"
inCluster: "true"
```
## Related topics

* [Symphony lightweight polling agent (Piccolo)](./piccolo-agent.md)


157 changes: 157 additions & 0 deletions docs/symphony-book/agent/symphony-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Symphony agent

_(last edit: 6/4/2024)_

A Symphony agent runs on a `target` and provides several services to Symphony payloads running on the same target, including:

* Get object references from the control plane.
* Probe and report on health of associated `device` objects.
* Capture and upload camera images for camera `device` objects.

A Symphony agent is a microservice that exposes an HTTP endpoint to Symphony payloads. We offer a Symphony container (`ghcr.io/eclipse-symphony/symphony-agent`) as well as a cross-platform binary that can be configured as a system daemon or service.

## Prepare for Symphony agent deployment

In this example, the Symphony agent needs a service principal to access an Azure Storage account to upload camera snapshots. In the current version of Symphony, we support service principal with a secret.

1. Create a service principal. For more information, see [Azure SDK for GO authentication with a service principal](https://learn.microsoft.com/azure/developer/go/azure-sdk-authentication-service-principal?tabs=azure-cli).

```azurecli
# create resource group
az group create --name <resource group name> --location <location>
# create key vault
az keyvault create --location <location> --name <key vault name> --resource-group <resource group name>
# create service principal
az ad sp create-for-rbac --name <service principal name> --role Contributor --scope /subscriptions/<subscription id>/resourceGroups/<resource group name>
```

Copy the `password` output before closing your terminal window.

> **NOTE:** we'll support certificate-based principals in future versions.

2. If needed, create an Azure Storage account and a container for storing the snapshots:

```bash
az storage account create --name <storage account name> --resource-group <resource group name> --location <location> --sku Standard_LRS
az storage container create -n snapshots --account-name <storage account name>

# grant permission to access storage account
az role assignment create --assignee <service principal app id> --role "Storage Blob Data Owner" --scope /subscriptions/<subscription id>/resourceGroups/<resource group name>/providers/Microsoft.Storage/storageAccounts/<storage account name>
```

3. If you plan to run Symphony agent as a process or a service, install [FFmpeg](https://ffmpeg.org/) on your target machine. You can skip this step if you plan to run Symphony agent as a container, which has FFmpeg pre-installed.

```bash
sudo apt update
sudo apt install ffmpeg
# verify installation
ffmpeg -version
```

## Option 1: Run Symphony agent as a container

To test Symphony agent on your local dev machine, you can use the prebuilt container:

```bash
docker run -p 8088:8088 -e SYMPHONY_URL=http://<Symphony control plane endpoint>:8080/v1alpha2/agent/references -e AZURE_CLIENT_ID=<service principal app id> -e AZURE_TENANT_ID=<service principal tenant id> -e AZURE_CLIENT_SECRET=<service principal client secret> -e STORAGE_ACCOUNT=<storage account name> -e STORAGE_CONTAINER=<storage container name> -e TARGET_NAME=<target name> eclipse-symphony/symphony-agent:0.1.26
```

Where `<Symphony control plane endpoint>` is the DNS/IP of Symphony control plane endpoint. For example, when you run Symphony control plane on a Kubernetes cluster, the control plane exposes a load-balanced service endpoint for agents. You can get the service endpoint with:

```bash
kubectl get svc symphony-service-ext #use returned EXTERNAL-IP to connect
```

## Option 2: Run Symphony agent as a process

To run Symphony agent as a process, you need to set required environment variables first, and then launch the agent:

```bash
export AZURE_CLIENT_ID=<service principal app id>
export AZURE_TENANT_ID=<service principal tenant id>
export AZURE_CLIENT_SECRET=<service principal client secret>
export STORAGE_ACCOUNT=<storage account name>
export STORAGE_CONTAINER=<storage container name>
export SYMPHONY_URL=http://<symphony API address>:8080/v1alpha2/agent/references # point to your local Symphony API endpoint, or the public Symphony API service endpoint on K8s
export TARGET_NAME=<target name> #the name of the Target object representing the current compute device

./symphony-agent -c ./symphony-agent.json -l Debug
```

## Get object reference

You can get Symphony object specs, such as AI [skill](../concepts/unified-object-model/ai-skill.md) and [solution](../concepts/unified-object-model/solution.md), through the Symphony agent:

* **Route**: `http://<Symphony agent endpoint>:8088/v1alpha2/agent/references`
* **Method**: GET
* **Parameters**:

| Parameter | Comment |
|--------|--------|
| alias | AI Skill alias<sup>1</sup>|
| field-selector | Field selector (optional), for example: `metadata.name=redis-server`|
| group | Resource group, like `ai.symphony`, `solution.symphony` and `fabric.symphony`|
| id | Resource name (optional)|
| instance | Solution instance id<sup>1</sup>|
| kind | Resource kind, like `skills`, `solutions` and `devices`|
| label-selector | Label selector (optional), for example: `foo=bar`|
| ref | Reference provider type. Use `v1alpha2.ReferenceK8sCRD` to query K8s objects |
| namespace | Namespace, like `default`|
| version | Resource version, like `v1`|

**<sup>1</sup>**: This parameter is supposed to be used in `skill` queries only. When supplied, `skill` parameter values will be overridden by corresponding values (named as `<skill name>.<parameter name>`) in the `instance` object. In addition, if the `alias` parameter is specified, Symphony uses `<skill name>.<alias>.<parameter name>` to locate instance overrides instead. For more information, see [parameter management](../ai-management/parameter-management.md).

The reference endpoint can also be used to resolve Azure Custom Vision model download URLs. Some addition parameters are used for such queries:

| Parameter | Comment |
|--------|--------|
| flavor | Custom Vision model export flavor (such as `TensorFlowNormal`)|
| lookup |set to `download` when querying download URLs|
| iteration | Custom Model iteration |
| platform| Custom Vision model export platform (such as `TensorFlow`)|

> **NOTE** if `flavor` and `platform` are omitted, the reference endpoint only returns existing exports. If both are provided, the reference endpoint will request a new export if necessary (such as when existing exports have expired).

### Examples

* Get AI Skill with name `cv-model`:

```bash
http://localhost:8088/v1alpha2/agent/references?scope=default&kind=skills&version=v1&group=ai.symphony&id=cv-model&&ref=v1alpha2.ReferenceK8sCRD
```

* List AI Skill with label `foo=bar`:

```bash
http://localhost:8088/v1alpha2/agent/references?scope=default&kind=skills&version=v1&group=ai.symphony&label-selector=foo=bar&&ref=v1alpha2.ReferenceK8sCRD
```

* Get AI Skill with name `sv-skill`, overwrite its parameters with values in instance `dummy-instance`, aliased as `abc`. For more information, see [parameter management](../ai-management/parameter-management.md).

```bash
http://localhost:8088/v1alpha2/agent/references?scope=default&kind=skills&version=v1&group=ai.symphony&id=cv-skill&ref=v1alpha2.ReferenceK8sCRD&instance=dummy-instance&alias=abc
```

## Report object state

You can report object state through Symphony agent.

* **Route**: `http://<Symphony agent endpoint>:8088/v1alpha2/agent/references`
* **Method**: POST
* **Parameters**:
| Parameter | Comment |
|--------|--------|
| group | Resource group, like `ai.symphony`, `solution.symphony`, and `fabric.symphony` |
| id | Resource name (optional)|
| kind | Resource type, like `skills`, `solutions`, and `devices`|
| overwrite | If set to true, the object state will be reset to reported properties. Otherwise, the reported properties are merged into existing state (optional, default = false) |
| namespace | Namespace, like `default` |
| version | resource version, like `v1` |

* **Body**: A key-value pair collection of reported properties

>**NOTE:** Symphony always reports object state as a key-value collection named `properties`.

## Capture camera frame

Capturing camera frames happens automatically, and captured image URL will be reported as part of `device` state as a `snapshot` property.
Loading
Loading