# Akri Instance Naming Convention This document details how Akri names Instance Custom Resources. This information can be used to predict the name of the Kubernetes Resource (made by Akri) of a device. ## Background Say you are using GitOps to deploy Akri and workloads to discovered devices. In this scenario, instead of using the controller, you choose to use Flux to apply/sync Deployments/DaemonSets/ReplicaSets that use devices discovered by Akri. Since Akri consistently names devices, the naming of a device can be predicted. This means that if you have a device registry of devices you expect to discover, you can redeploy your setup and request the expected Kubernetes Resources. ## Instance naming convention overview In the case of network-based devices, an Akri Instance's name is dependent on two things: the Akri Configuration name (configured via helm with `--set opcua.configuration.name=some-name`) and the id returned by the Discovery Handler. This id varies by Discovery Handler -- see the [implementation details section](#Implementation-details) for how to find this in Akri's code. For OPC UA, the id of the discovered OPC UA server is simply the OPC UA Discovery Url. This ID is then put through a [BLAKE2](https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2) hash and concatenated with the Configuration name. In summary, instance name is the following where discovery_url could be `opc.tcp://10.0.0.1:5657/` for example: **`INSTANCE_NAME = format!("{}-{}", config_name, blake_hash(discovery_url))`** Then this server could be requested for a workload by adding it as a resource request to a ContainerSpec in a Kubernetes Object (Job, Deployment, ReplicaSet, etc), like follows – see our [docs](https://docs.akri.sh/user-guide/requesting-akri-resources) for more details on resource requesting: ```yaml resources: limits: akri.sh/$INSTANCE_NAME: "1" requests: akri.sh/$ INSTANCE_NAME: "1" ``` ### Implementation details Tracing the above flow in Akri's code: 1. The OPC UA discovery handler returns the discoveryUrl ID [here](https://github.com/project-akri/akri/blob/45dcd532a5a09bd8a62aa89e6cea63669ae94bcf/discovery-handlers/opcua/src/discovery_handler.rs#L122) 2. This is then hashed by [this function](https://github.com/project-akri/akri/blob/45dcd532a5a09bd8a62aa89e6cea63669ae94bcf/agent/src/util/discovery_operator.rs#L713). Note how local devices are also identified by their node. ```rust= pub fn inner_generate_instance_digest( id_to_digest: &str, shared: bool, query: &impl EnvVarQuery, ) -> String { let mut id_to_digest = id_to_digest.to_string(); // For local devices, include node hostname in id_to_digest so instances have unique names if !shared { id_to_digest = format!( "{}{}", &id_to_digest, query.get_env_var("AGENT_NODE_NAME").unwrap() ); } let mut digest = String::new(); let mut hasher = VarBlake2b::new(3).unwrap(); hasher.update(id_to_digest); hasher.finalize_variable(|var| { digest = var .iter() .map(|num| format!("{:02x}", num)) .collect::<Vec<String>>() .join("") }); digest } ``` 3. Then this id is concatenated with the the name of the Configuration custom resource that was used to intialize Akri to discover the device. Specifically is generated by the following function [here](https://github.com/project-akri/akri/blob/45dcd532a5a09bd8a62aa89e6cea63669ae94bcf/agent/src/util/device_plugin_service.rs#L747): ```rust= pub fn get_device_instance_name(id: &str, config_name: &str) -> String { format!("{}-{}", config_name, &id) .replace(".", "-") .replace("/", "-") } ```