Our first blog post focused strongly on why—why we created Capact, what's the general concept behind it. Now it's time for showing how—how you can use it.
Although, there are many ways to get started with Capact, today we will focus on your perspective as a Capact User.
The recommended way to try out Capact quickly is to set up a local environment.
Detailed instructions are already nicely described in our local installation tutorial. Once you have Capact up and running, we can start!
What you will learn
info
For this blog post, we will use Capact CLI. However, the described scenario can also be executed with our brand-new UI! 😎
In 5 minutes, by running examples from this blog post, you will learn about the following Capact concepts:
- Interface—provides an option to abstract Implementations.
- Implementation—defines the actual workflow that is executed.
- Attribute—provides an option to tag manifests. Today we will use it to select a specific Implementation.
- Type and TypeInstance—provide a combined feature, where Type holds the schema and TypeInstance the instance for the Type.
- Action—triggers Engine to render and run a given Interface.
- Policy—impacts the render process to select desired Implementations.
Creating new workflows is not the concern of this article, and it will be covered in future blog posts.
Here we only briefly describe each part, but I encourage you to take a deeper look at our Terminology section later.
Prerequisites
- Capact CLI at least v0.6.0
- Capact cluster at least v0.6.0
- (Optional)
kubectl
jq
Scenario
The key concepts were described in the Introducing Capact blog post. There, we used Mattermost as an example. It was a real life scenario but at the same time more resource and time-consuming.
For the purpose of this blog post, we created an extremely simple Hello World example.
There are two Implementations for the cap.interface.capactio.examples.say
Interface. Depending on the Policy, a different Implementation is selected. By default, Engine selects the Implementation which is first on the list (alphabetical order) and doesn't have any requirements regarding executions, such as requiring AWS credentials.
Camera, Lights, Action!
Action is the entry point for executing any Interface. It allows you to define which Interface should be executed and with which parameters. This is later consumed by Capact Engine and the appropriate workflow is rendered. Later, you can review it and approve it for the execution.
Steps
List available Interfaces:
capact hub interfaces get
We are interested in this part:
PATH LATEST REVISION IMPLEMENTATIONS
---------------------------------------+-----------------+-----------------------------------------------
# ... trimmed ...
---------------------------------------+-----------------+-----------------------------------------------
cap.interface.capactio.examples.greet 0.1.0 cap.implementation.capactio.examples.greet
---------------------------------------+-----------------+-----------------------------------------------
cap.interface.capactio.examples.say 0.1.0 cap.implementation.capactio.examples.hello
cap.implementation.capactio.examples.rickyCreate a new Action:
- Default Execution
- Policy-Changed Execution
note
A Policy is not needed as we use the default behavior here.
capact act create --name hello cap.interface.capactio.examples.greet
First, save the Policy to the /tmp/policy.yaml
file:
cat <<EOF > /tmp/policy.yaml
rules:
- interface:
path: cap.interface.capactio.examples.say
oneOf:
- implementationConstraints:
attributes:
- path: cap.attribute.capactio.examples.be-positive
revision: 0.1.0
EOF
Next, create the Action with the Policy:
capact act create --name hello cap.interface.capactio.examples.greet --action-policy-from-file /tmp/policy.yaml
Wait for the Action to have the
READY_TO_RUN
status:capact act get hello
When the status is
READY_TO_RUN
, run the Action:capact act run hello
Watch the progress:
capact act watch hello
(Optional) Once the Action is finished, copy the name of the Pod for the
print
workflow step (columnPODNAME
). To read its logs, run:kubectl logs {PODNAME} main
Example output:
- Default Execution
- Policy-Changed Execution
____________________________
< message: Hello from Capact >
----------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
__________________________________
< message: Never gonna give you up >
----------------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
Get the Action output (TypeInstance). Copy the
id
field value:capact act get hello -ojson | jq '.Actions[0].output.typeInstances'
Example output:
[
{
"id": "08fcaa07-7846-47af-b6a7-7c3818c69656",
"typeRef": {
"path": "cap.type.capactio.examples.message",
"revision": "0.1.0"
}
}
]Get the TypeInstance
value.message
field value:capact ti get {ID} -ojson | jq -r '.[0].latestResourceVersion.spec.value.message'
Delete the Action:
capact act delete hello
What if you wanted to output a different message, that reminds you about a masterpiece song you can listen to endlessly? With Capact that's really easy ✨
To choose a different Implementation for the say
Interface, we need to prepare a dedicated Policy. The power of it is that you don't have to change the main workflow. You treat the step as a building block and just swap it for another existing one.
To test it, execute steps once again, but now select the Policy-Changed Execution tab.
What is so special about it?
Our example was simplified to a minimum, but you could see that you can:
- chain different steps together,
- and more importantly, write once and swap implementation details with ease.
Capact is also great if you want to chain different tools together and keep the same entry point (UX) but that requires more complex examples. For now, we recommend you to take a look at our other examples described in the How can I get involved and learn more? section.
Behind the CLI
As you saw, you can use CLI to browse Hub manifests, create a specific Action for a given Interface and retrieve the output. CLI communicates with our Gateway via GraphQL calls, same as the UI (Capact Dashboard). You can read more in the E2E Architecture document.
However, a more important question is, how did it happen?
spec:
# ... trimmed ...
imports:
- interfaceGroupPath: cap.interface.capactio.examples
alias: examples
methods:
- name: say
# ... trimmed ...
steps:
- - name: get-message
capact-action: examples.say # dynamic step, rendered by Engine based on the Policy.
- - name: print
template: print
arguments:
artifacts:
- name: message
from: "{{steps.get-message.outputs.artifacts.message}}"
# ... trimmed ...
- name: print
inputs:
artifacts:
- name: message
path: /tmp/message.yaml
container:
image: docker/whalesay:latest
command: [ sh, -c ]
args: [ "cowsay < /tmp/message.yaml" ]
The snippet above shows the most important parts of the Implementation manifest. In lines 4-7, we declare the import, which is later used in steps. In line 12, we use capact-action to make a dynamic step with a given Interface.
tip
Instead of providing the full Interface path, we use alias assigned to the imported Interface.
As a result, our Engine and, in particular, Argo Renderer has an option to put there an Implementation that fulfills the specified Interface. Thanks to that, this step is swappable based on the defined Policy.
How can I get involved and learn more?
The Getting Started goes into more detail about how to start with Capact and use its more-advanced features. There are also Rocket.Chat and Mattermost tutorials that we keep up-to-date for you to walk you through using Capact in real cases.
We appreciate any input you have about your experience with Capact!
There are plenty of options to contact us:
- GitHub issues
- Slack
- Email us at [email protected]
Thank you for taking the time to learn about Capact 🙌