What's a Target?

A Foundries Factory is a unique new concept. Conceptualizing a Factory can sometimes seem difficult. I've encountered this enough to see a common problem - we are looking at things the wrong way.

In order to understand a Factory you have to first understand the goal: delivering immutable software to devices. Security, Git, Docker, etc are just the means to this end. The way we choose to deliver software is based on The Update Framework, TUF. TUF has a concept of Targets. A Target is a description of the software a device should run. Here's a simplified example:

  "raspberrypi3-64-lmp-44" : {
    "hashes" : {"sha256" : "0xdeadbeef"},
    "custom" : {
      "version" : "44"
      "docker_compose_apps" : {
        "shellhttpd" : {
          "uri" : "hub.foundries.io/andy-corp/[email protected]:0xdeadbeef"
        }
      },
      "hardwareIds" : ["raspberrypi3-64"],
      "tags" : ["master"],
    }
  }

The Target shown is the goal. It provides all the information necessary for a device to decide whether or not it should be running that Target. The device looks at this target and asks "Am I a raspberrypi3-64? Am I running Targets with the master tag? Am I running something older than build 44?" If the answers are "yes", then it can install this immutable collection of software onto the device.

The point of the Factory is to create Targets. The magic of the Factory is how easy we make it to create these Targets. This is where we can start to conceptualize a Factory. Each Factory includes its own factory definition file. This file instructs us on how to react to your company's development process (i.e. what to do with source code changes). In the most common and simple case, it usually tells us a few simple things like:

  • If we see a change to an LMP source repo on branch "master", we should produce a build and tag the resultant Target with "master".
  • If we see a container change on the "devel" branch, we should produce a Target tagged with "devel".

It can grow much more complex.

So - how do you visualize your Factory? Start with your factory-config.yml file. That defines what code we take and how we create Targets for you. Then take a high-level look at your fleet with:

$ fioctl status
Total number of devices: 2

TAG     DEVICES  UP TO DATE  ONLINE
---     -------  ----------  ------
master  2        1           1

## Tag: master
    TARGET  DEVICES  DETAILS
    ------  -------  -------
    46      1           fioctl targets show 46
    112     1           fioctl targets show 112

From there you get a picture of which Targets are active. You can then view the details of a Target to understand what caused it to be created:

$ fioctl targets show 46
Tags:    master
CI:    https://ci.foundries.io/projects/andy-corp/lmp/builds/46/
Source:
    https://source.foundries.io/factories/andy-corp/lmp-manifest.git/commit/?id=aa36b74580d64f8754d42817e534004c05f80cf7
    https://source.foundries.io/factories/andy-corp/meta-subscriber-overrides.git/commit/?id=d56ae6a677316bf1c8544cf9228632a59fe3d991
    https://source.foundries.io/factories/andy-corp/containers.git/commit/?id=749aac2cc30c572769b702498373505dac1da7ed

TARGET NAME             OSTREE HASH - SHA256
-----------             --------------------
raspberrypi3-64-lmp-46  cda90aebd6872e635eaeb9ddd67ba6dd198840382def48f16e86c1b22520c6a7

COMPOSE APP  VERSION
-----------  -------
shellhttpd   hub.foundries.io/andy-corp/[email protected]:e4a7b3a31c0126d28aaf75e1b8b6e83c7afd160b110267530b8572ce192160da
helloworld   hub.foundries.io/andy-corp/[email protected]:5cf0989698df971f618523d750e7d25cb1a93df62c2783119154bf4fe948caca

This command shows the details of the Target. The CI URL will include the exact Git change that triggered things as well as all the source code that produced this Target.

But ...

"I'm an application developer. I don’t care about platform code."

The good news is that you don't have to. The bad news is that your containers can't run without a platform. The better news - when you tell us about your containers.git branches in the factory definition, we do the worrying for you. For example:

  tagging:
    refs/heads/master:
    - tag: postmerge
    refs/heads/devel:
    - tag: devel:postmerge

That tells us that when you push to "master" that you want to create a new Target tagged with "postmerge". We'll look through your targets.json and find the most recent Target with that tag. We'll then grab the platform(ostree hash) from that to create your new Target. When you push to "devel", we create a new Target with the tag "devel", but it will grab the most recent Platform (ostree hash) from "postmerge".

"I'm a platform developer. I don’t care about application code."

The good news is that you don't have to. The bad news is that your i2c driver needs something in userspace to consume it. The better news - your factory definition tells us how to handle this for you. For example:

  tagging:
    refs/heads/master:
    - tag: postmerge

This tells us that each change to master should produce a new Target with the "postmerge" tag. We know to look at the previous Target's Docker Apps and copy them into this new Target.

"I'm an Ops person. I don't care about application or platform code"

You need traceability. Hopefully this article gives you a mental model for doing that.

So no matter your place in the org chart, the Target provides you insight into what matters most to you.

Keep up to date with Foundries.io