Building a Stack

The Stack is the definition of your infrastructure that Opslib will manage. It’s made up of components, with the root component being an instance of Stack.

stack.py
from opslib import Stack

stack = Stack(__name__)

Opslib tries to import a module named stack (which is why our file is called stack.py). In the module, it looks for an object named stack.

The __name__ argument helps Opslib figure out where the code is defined, so it can create its .opslib directory, next to stack.py, to store its state.

Attaching components

To build up the stack, we attach components to it, by setting them as attributes:

from pathlib import Path
from opslib import LocalHost

stack.host = LocalHost()
stack.hello = stack.host.file(
    path=Path("/tmp/hello.txt"),
    content="Hello World!\n"
)

At this point, the host and hello components are attached to the stack, and will be deployed when we run opslib - deploy.

$ opslib - deploy
$ cat /tmp/hello.txt
Hello World!

Defining components

Attaching everything to the root stack object doesn’t scale much, so we’ll want to organize components into higher level structures:

from opslib import Component, Prop

class Bucket(Component):
    class Props:
        host = Prop(LocalHost)
        color = Prop(str)

    def build(self):
        self.file = self.props.host.file(
            path=Path(f"/tmp/{self.props.color}.txt"),
            content=f"A splash of {self.props.color}\n"),
        )

stack.red = Bucket(host=stack.host, color="red")
stack.green = Bucket(host=stack.host, color="green")
stack.blue = Bucket(host=stack.host, color="blue")

The Bucket component receives two Props: host and color.

The component’s build() method creates sub-components and attaches them. It’s called when the Bucket component is attached to something (in our case, the stack).

Note

build() is not called when the component is created, but rather later, when it’s attached. This means that a detached component doesn’t have any of its child components created and attached yet.