Welcome to the user guide on packaging the Helm chart for the hello-world microservice into a CSAR (Cloud Service Archive) with Automation Composition Management (ACM) definitions. This guide is designed to help you seamlessly integrate your microservices into an ACM-enabled Kubernetes environment, enabling efficient orchestration and management.
As organizations embrace microservices architecture, the need for effective orchestration and automation becomes critical. Automation Composition Management (ACM) provides a solution by allowing users to define, deploy, and manage complex microservice compositions seamlessly.
This documentation focuses on packaging a Helm chart, which encapsulates the hello-world microservice, into a CSAR. The CSAR includes not only the Helm chart for deployment but also ACM definitions that specify how the microservice should be orchestrated and interact with other components in your Kubernetes environment.
Before you proceed, please ensure that the following prerequisites are met:
Now, let's dive into the step-by-step process of packaging your Helm chart into a CSAR with ACM definitions for a seamless integration with ACM in your Kubernetes environment.
In this section, we provide a high-level overview of the process of packaging the Helm chart for the hello-world microservice into an rApp Package. This packaging process enables you to create a Cloud Service Archive (CSAR) that not only includes the Helm chart for deployment but also integrates Automation Composition Management (ACM) definitions, TOSCA metadata, and essential metadata files. This integration ensures seamless orchestration and management of your microservices within a Kubernetes environment.
The rApp Package combines the strengths of Helm for microservice deployment with the orchestration capabilities of ACM in a Kubernetes environment. ACM ensures that your microservices are deployed and configured according to defined compositions, allowing for flexibility and adaptability in complex scenarios.
Now, let's proceed with the step-by-step guide to package your Helm chart into an rApp Package with ACM definitions for deployment in your Kubernetes environment.
The rApp Generator simplifies the process of creating a Cloud Service Archive (CSAR) package, including Automation Composition Management (ACM) definitions, for your microservices. This guide outlines the directory structure, contents, and the steps involved in using the `generate.sh` script to generate a CSAR package.
rapp-hello-world
|-- definitions
-- asd.yaml
-- asd_types.yaml
|-- files
-- Acm
-- definition
-- compositions.json
-- instances
-- k8s-instance.json
|-- TOSCA-Metadata
-- TOSCA.meta
|-- asd.mf
|-- generate.sh
|-- generate.bat
TOSCA is a standard for describing the topology and orchestration of cloud applications. The asd.yaml and asd_types.yaml files conform to the TOSCA specification and defining the application service descriptor (ASD) and related types. They describe the structure and properties of the application service, its components, and configurations.
The file containing ACM compositions must be named compositions.json. This JSON file defines the ACM compositions for the rApp. It includes data types, node types, and a topology template specifying the structure of the compositions. ACM compositions define how the application components interact. They specify the structure of the automation composition and the types of components involved.
This JSON file represents an instance of the ACM composition. It specifies the name, version, and properties of the instance, including the elements involved (e.g., K8S microservice) and their configurations. In this case, it includes information about the K8S microservice. While there is no strict naming convention for instance files, it is recommended to use descriptive names that reflect the purpose or content of the instance.
This file provides metadata about the CSAR. It includes the CSAR version, TOSCA meta-file version, the entry definition file, and ETSI-specific information.
This file contains metadata for the application service descriptor (ASD). It includes information such as the application name, provider, release date/time, and entry definition type. It also lists the sources for the CSAR, including TOSCA files and ACM definition files.
Prepare your rApp Resources:
- Organize ASD definitions, ACM compositions, instance files, and TOSCA Metadata in the designated directory structure.
Run the `generate.sh` Script:
- Execute the `generate.sh` script, providing the rApp resource folder name as a parameter.
./generate.sh rapp-hello-world
Verification:
- Check for any error messages during the CSAR generation process.
- Verify that the CSAR file (`rapp-hello-world.csar`) is generated in the same directory.
Result:
- Once the process is complete, the script will indicate that the rApp package has been generated successfully.
rApp package rapp-hello-world.csar generated.
To construct a seamless ACM topology for Kubernetes (k8s), it is imperative to adhere to a comprehensive TOSCA definition that encapsulates essential elements.
The following code snippets provide a foundational framework, encompassing data types, node types, and specific configurations necessary for a robust ACM deployment:
{ "tosca_definitions_version": "tosca_simple_yaml_1_3", "data_types": { "onap.datatypes.ToscaConceptIdentifier": { "derived_from": "tosca.datatypes.Root", "properties": { "name": { "type": "string", "required": true }, "version": { "type": "string", "required": true } } } }, "node_types": { "org.onap.policy.clamp.acm.Participant": { "version": "1.0.1", "derived_from": "tosca.nodetypes.Root", "properties": { "provider": { "type": "string", "required": false } } }, "org.onap.policy.clamp.acm.AutomationCompositionElement": { "version": "1.0.1", "derived_from": "tosca.nodetypes.Root", "properties": { "provider": { "type": "string", "required": false }, "participantType": { "type": "onap.datatypes.ToscaConceptIdentifier", "required": true }, "startPhase": { "type": "integer", "required": false, "constraints": [ { "greater-or-equal": 0 } ], "metadata": { "common": true }, "description": "A value indicating the start phase in which this automation composition element will be started, the first start phase is zero. Automation Composition Elements are started in their start_phase order and stopped in reverse start phase order. Automation Composition Elements with the same start phase are started and stopped simultaneously" }, "passiveToRunningTimeout": { "type": "integer", "required": false, "constraints": [ { "greater_or_equal": 0 } ], "default": 60, "metadata": { "common": true }, "description": "The maximum time in seconds to wait for a state chage from passive to running" }, "runningToPassiveTimeout": { "type": "integer", "required": false, "constraints": [ { "greater_or_equal": 0 } ], "default": 60, "metadata": { "common": true }, "description": "The maximum time in seconds to wait for a state chage from running to passive" }, "passiveToUninitializedTimeout": { "type": "integer", "required": false, "constraints": [ { "greater_or_equal": 0 } ], "default": 60, "metadata": { "common": true }, "description": "The maximum time in seconds to wait for a state chage from passive to uninitialized" } } }, "org.onap.policy.clamp.acm.AutomationComposition": { "version": "1.0.1", "derived_from": "tosca.nodetypes.Root", "properties": { "provider": { "type": "string", "required": false, "metadata": { "common": true } }, "elements": { "type": "list", "required": true, "metadata": { "common": true }, "entry_schema": { "type": "onap.datatypes.ToscaConceptIdentifier" } } } }, "org.onap.policy.clamp.acm.K8SMicroserviceAutomationCompositionElement": { "version": "1.0.0", "derived_from": "org.onap.policy.clamp.acm.AutomationCompositionElement", "properties": { "chart": { "type": "string", "required": true }, "configs": { "type": "list", "required": false }, "requirements": { "type": "string", "required": false }, "templates": { "type": "list", "required": false, "entry_schema": null }, "values": { "type": "string", "required": true } } } }, "topology_template": { "node_templates": { "org.onap.k8s.acm.K8SAutomationCompositionParticipant": { "version": "2.3.4", "type": "org.onap.policy.clamp.acm.Participant", "type_version": "1.0.1", "description": "Participant for K8S", "properties": { "provider": "ONAP" } }, "onap.policy.clamp.ac.element.K8S_StarterAutomationCompositionElement": { "version": "1.2.3", "type": "org.onap.policy.clamp.acm.K8SMicroserviceAutomationCompositionElement", "type_version": "1.0.0", "description": "Automation composition element for the K8S microservice for AC Element Starter", "properties": { "provider": "ONAP", "startPhase": 0, "uninitializedToPassiveTimeout": 300, "podStatusCheckInterval": 30 } }, "onap.policy.clamp.ac.element.AutomationCompositionDefinition": { "version": "1.2.3", "type": "org.onap.policy.clamp.acm.AutomationComposition", "type_version": "1.0.1", "description": "Automation composition for rapp deployment", "properties": { "provider": "ONAP", "elements": [ { "name": "onap.policy.clamp.ac.element.K8S_StarterAutomationCompositionElement", "version": "1.2.3" } ] } } } } } |
The provided ACM TOSCA definition includes key elements necessary for defining an ACM topology for Kubernetes (k8s). However, to avoid errors, ensure that the definitions are complete and correctly referenced.
The ACM TOSCA definition includes key data types and node types such as ToscaConceptIdentifier
, Participant
, AutomationCompositionElement
, AutomationComposition
, and K8SMicroserviceAutomationCompositionElement
. These definitions represent building blocks for ACM topologies, specifically for Kubernetes deployments.
ToscaConceptIdentifier:
name
and version
.Participant:
provider
(optional).AutomationCompositionElement:
provider
(optional), participantType
(referencing ToscaConceptIdentifier
), and additional timing-related properties.AutomationComposition:
provider
(optional), elements
(list of ToscaConceptIdentifier
).K8SMicroserviceAutomationCompositionElement:
AutomationCompositionElement
.chart
, configs
, requirements
, templates
, and values
.Topology Template:
Participant Definition:
Participant
definitions are referenced correctly in node templates.Automation Composition Element:
AutomationCompositionElement
in the node templates and ensure correct referencing of the ToscaConceptIdentifier
for participantType
.Automation Composition:
AutomationCompositionElement
in the AutomationComposition
definition.K8S Microservice Automation Composition Element:
K8SMicroserviceAutomationCompositionElement
is used for Kubernetes-specific compositions.Top-Level Node Templates:
K8SAutomationCompositionParticipant
and others should reference the appropriate definitions.When utilizing the provided ACM TOSCA definition for Kubernetes (k8s), it is essential to include all key elements to define the ACM topology accurately. Failure to incorporate required definitions may lead to errors during the deployment process. Common indicators of missing components include repeated YAML separator lines (---
) and unexpected empty sections. To illustrate, if the definitions for org.onap.policy.clamp.acm.AutomationCompositionElement
or org.onap.policy.clamp.acm.Participant
are absent, errors such as NullPointerException
or unexpected behavior during deployment might occur. Therefore, it is crucial to thoroughly review and complete the TOSCA definition, ensuring all necessary components are correctly specified to avoid potential issues.
ToscaConceptIdentifier
, Participant
, etc.) are correctly defined and referenced.For instance, if the definitions for org.onap.policy.clamp.acm.AutomationCompositionElement
or org.onap.policy.clamp.acm.Participant
are absent, errors such as NullPointerException
or unexpected behavior during deployment might occur.
java.lang.NullPointerException: Cannot invoke "org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate.getProperties()" because the return value of "java.util.Map.get(Object)" is null at com.oransc.rappmanager.models.AcmInterceptor.injectToscaServiceTemplate(AcmInterceptor.java:57) ~[rapp-manager-models-0.1.0-SNAPSHOT.jar!/:0.1.0-SNAPSHOT] at com.oransc.rappmanager.dme.service.DmeAcmInterceptor.injectToscaServiceTemplate(DmeAcmInterceptor.java:68) ~[rapp-manager-dme-0.1.0-SNAPSHOT.jar!/:0.1.0-SNAPSHOT] at com.oransc.rappmanager.acm.service.AcmDeployer.createComposition(AcmDeployer.java:85) ~[rapp-manager-acm-0.1.0-SNAPSHOT.jar!/:0.1.0-SNAPSHOT] at com.oransc.rappmanager.acm.service.AcmDeployer.primeRapp(AcmDeployer.java:187) ~[rapp-manager-acm-0.1.0-SNAPSHOT.jar!/:0.1.0-SNAPSHOT] at com.oransc.rappmanager.service.RappService.lambda$primeRapp$0(RappService.java:53) ~[!/:0.1.0-SNAPSHOT] at java.base/java.util.stream.MatchOps$1MatchSink.accept(Unknown Source) ~[na:na] at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(Unknown Source) ~[na:na] at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(Unknown Source) ~[na:na] at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(Unknown Source) ~[na:na] at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) ~[na:na] at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) ~[na:na] at java.base/java.util.stream.MatchOps$MatchTask.doLeaf(Unknown Source) ~[na:na] at java.base/java.util.stream.MatchOps$MatchTask.doLeaf(Unknown Source) ~[na:na] at java.base/java.util.stream.AbstractShortCircuitTask.compute(Unknown Source) ~[na:na] at java.base/java.util.concurrent.CountedCompleter.exec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinPool.scan(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinPool.runWorker(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source) ~[na:na] |
java.lang.NullPointerException: Cannot invoke "org.onap.policy.clamp.models.acm.concepts.AutomationComposition.getElements()" because "automationComposition" is null at com.oransc.rappmanager.models.AcmInterceptor.injectAutomationComposition(AcmInterceptor.java:84) ~[rapp-manager-models-0.0.1.jar!/:0.0.1] at com.oransc.rappmanager.acm.service.AcmDeployer.deployRappInstance(AcmDeployer.java:141) ~[rapp-manager-acm-0.0.1.jar!/:0.0.1] at com.oransc.rappmanager.service.RappService.deployRappInstance(RappService.java:106) ~[!/:0.0.1] at com.oransc.rappmanager.rest.RappInstanceController.lambda$deployRappInstance$10(RappInstanceController.java:95) ~[!/:0.0.1] at java.base/java.util.Optional.map(Unknown Source) ~[na:na] at com.oransc.rappmanager.rest.RappInstanceController.lambda$deployRappInstance$12(RappInstanceController.java:95) ~[!/:0.0.1] at java.base/java.util.Optional.map(Unknown Source) ~[na:na] at com.oransc.rappmanager.rest.RappInstanceController.deployRappInstance(RappInstanceController.java:93) ~[!/:0.0.1] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na] |
The following example showcases an ACM instance designed for Kubernetes deployment:
{ "name": "DemoInstance0", "version": "1.0.1", "compositionId": "COMPOSITIONID", "description": "Demo automation composition instance 0", "elements": { "709c62b3-8918-41b9-a747-d21eb79c6c21": { "id": "709c62b3-8918-41b9-a747-d21eb79c6c21", "definition": { "name": "onap.policy.clamp.ac.element.K8S_StarterAutomationCompositionElement", "version": "1.2.3" }, "description": "Starter Automation Composition Element for the Hello World", "properties": { "chart": { "chartId": { "name": "hello-world-chart", "version": "0.1.0" }, "namespace": "nonrtric", "releaseName": "hello-world-chart", "podName": "hello-world-chart", "repository": { "repoName": "local", "address": "http://10.101.1.90:8879/charts" } } } } } } |
In this instance, "DemoInstance0" is specified with a version of "1.0.1," associated with a composition ID "COMPOSITIONID," and described as a demo automation composition. The instance contains a single element with the ID "709c62b3-8918-41b9-a747-d21eb79c6c21." This element is defined as the "K8S_StarterAutomationCompositionElement" with version "1.2.3." It represents the starter automation composition element for the Hello World service.
The element's properties include a reference to the Helm chart named "hello-world-chart" with version "0.1.0." The chart is intended for deployment in the "nonrtric" namespace with a release name, pod name, and repository details pointing to the local repository at "http://10.101.1.90:8879/charts."
This structured representation provides a clear overview of the ACM instance designed for deploying the Hello World service on Kubernetes.
To expose "Hello World" microservice endpoints through the Service Management and Exposure (SME), you need to create SME configurations and package them within the same rApp package that contains the Kubernetes participant.
The SME configuration consists of three directories: providers
, serviceapis
, and invokers
, each containing specific JSON files.
{ "apiProvDomInfo": "Provider domain", "apiProvFuncs": [ { "apiProvFuncInfo": "Hello World as APF", "apiProvFuncRole": "APF", "regInfo": { "apiProvPubKey": "APF-PublicKey" } }, { "apiProvFuncInfo": "Hello World as AEF", "apiProvFuncRole": "AEF", "regInfo": { "apiProvPubKey": "AEF-PublicKey" } } ], "regSec": "PSK" } |
{ "apiName": "Hello World API Set 1", "description": "Simple Hello World API", "aefProfiles": [ { "aefId": "Hello World as AEF", "description": "Simple Hello World API", "versions": [ { "apiVersion": "v1", "resources": [ { "resourceName": "helloworld", "commType": "REQUEST_RESPONSE", "uri": "/helloworld/v1", "operations": [ "GET" ] } ] } ], "protocol": "HTTP_1_1", "securityMethods": [ "PSK" ], "interfaceDescriptions": [ { "ipv4Addr": "string", "port": 30951, "securityMethods": [ "PKI" ] }, { "ipv4Addr": "string", "port": 30951, "securityMethods": [ "PKI" ] } ] } ] } |
[ { "apiInvokerInformation": "Invoker App 1", "apiList": [ {} ], "notificationDestination": "http://invoker-app1:8086/callback", "onboardingInformation": { "apiInvokerPublicKey": "{PUBLIC_KEY_INVOKER_1}", "apiInvokerCertificate": "apiInvokerCertificate" }, "requestTestNotification": true } ] |
After configuring SME, you can query the available APIs exposed by SME. Replace <NAMESPACE>
with your Kubernetes namespace.
CAPIF_HOST=http://$(kubectl get service capifcore -n nonrtric -o jsonpath='{.spec.clusterIP}'):8090 curl -sS --location "$CAPIF_HOST/service-apis/v1/allServiceAPIs?api-invoker-id=api_invoker_id_Invoker_App_1" --header 'Accept: application/json' | jq |
This command queries the SME to retrieve information about all available service APIs for the specified API invoker.