Skip to content

edgefarm.network Examples

This section contains examples of how to use the edgefarm.network API.

Complex Example

This example explains a complex scenario of how edgefarm.network can be used. The image shows the network architecture. Let's assume there are two applications called app1 and app2 that are deployed together on the same Edge Nodes and need to communicate with each other to form a final result. app1 might generate some sensor data and app2 uses these sensor data and filters them e.g. using a geo-located fence. The results generated by app2 need to be transported to the cloud where they can be processed further. Further let's assume that there are differnt kinds of Edge Nodes. Some with small disk capacity and some with large disk capacity leading to different data retention capabilities.

Network Architecture

To control the deployment we label our NodePools with app1/network=small and app1/network=big to distinguish between the different types of Edge Nodes.

Users

First the needed users are created in Network.spec.parameters.users

We create three users: app1 and app2 that can communicate with each other via some specific topics. app1 is able to publish some topics that app2 can subscribe to. In addition app2 is allowed to publish to topic3. So, both apps can work toghether to form a final result published on topic3 by app2. The user external-access can only subscribe to topic3.

Limits are set to -1 which means unlimited.

users:
  - name: "app1" #(1)!
    limits:
        payload: -1
        data: -1
        subscriptions: -1
    permissions:
      pub:
        allow:
          - "topic1.>"
          - "a.b.*.c.>"
        deny: []
      sub:
        allow: []
        deny: []
  - name: "app2" #(2)!
    limits:
        payload: -1
        data: -1
        subscriptions: -1
    permissions:
      pub:
        allow:
          - "topic3"
        deny: []
      sub:
        allow:
          - "topic1.>"
          - "a.b.*.c.>"
        deny: []
  - name: "external-access" #(3)!
    limits:
        payload: -1
        data: -1
        subscriptions: -1
    permissions:
      sub:
        allow:
          - "topic3"
        deny: []
      pub:
        allow: []
        deny: []
    writeToSecret:
      name: external-access-creds
  1. app1 is only allowed to publish to specific topics app2 is allowed to subscribe to.
  2. app2 is allowed to subscribe to app1 published topics is allowed to publish to topic3.
  3. external-access is only allowed to subscribe to a specific topic from app2. The connection credentials are stored in a specific secret that is accessible by the user by reading a Kubernetes secret.

Subnetworks

Now let's describe the different storage capabilities of the Edge Nodes. The first type is a small embedded Linux device with very limited storage capabilities while the other is a full blown server with lots of storage. However, we want both types of devices to be able to communicate and to utilize their storage capabilities.

To achieve this we can create two subnetworks: small and big. The small subnetwork will be used by the small embedded Linux devices while the big subnetwork will be used by the full blown servers. This way stream can be created for different subnetworks and the storage capabilities of the devices can be used. Eventually, each node with the corresponding node pool labeled with "app1/network=small" or "app1/network=big" will have an instance of this network.

subNetworks:
  - name: small
    limits:
      fileStorage: 300M
      inMemoryStorage: 10M
    nodepoolSelector:
      matchLabels:
        app1/network: small
  - name: big
    limits:
      fileStorage: 10G
      inMemoryStorage: 1000M
    nodepoolSelector:
      matchLabels:
        app1/network: big

Streams

Let's create the streams that are needed for the applications to communicate with each other. Streams can be added in Network.spec.parameters.streams.

This example creates one stream for each subnetwork, with barly the same configuration. The difference is the data retention for the stream on the small subnetwork is much shorter than the one on the big subnetwork. Both streams are configured to behave the same way when it comes to collecting subjects. These streams are meant for the user app1 to communicate with each other.

streams:
      - name: app-stream-small #(1)!
        type: Standard
        subNetworkRef: small
        config:
          subjects:
            - topic1.>
            - a.b.*.c.>
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 100000000 # 100MB

      - name: app-stream-big #(2)!
        type: Standard
        subNetworkRef: big
        config:
          subjects:
            - topic1.>
            - a.b.*.c.>
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 100000000 # 10GB

      - name: results-stream-small #(3)!
        type: Standard
        subNetworkRef: small
        config:
          subjects:
            - topic3
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 200000000 # 200MB

      - name: results-stream-big #(4)!
        type: Standard
        subNetworkRef: big
        config:
          subjects:
            - topic3
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 200000000 # 200MB

      - name: aggregate-stream #(5)!
        type: Aggregate
        references:
          - results-stream-small
          - results-stream-big
        config:
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 200000000 # 20GB
  1. The stream for app1 on the small subnetwork has only the size of 100 MB due to limited storage capabilities.
  2. The stream for app1 on the big subnetwork has the size of 10 GB due to large storage capabilities.
  3. The stream for app2 on the small subnetwork has only the size of 200 MB. This should be enough to store our final results.
  4. The stream for app2 on the big subnetwork is configured the same way as the one on the small subnetwork.
  5. The aggregate stream is used to aggregate the results from app2 on the small and big subnetwork. This stream is configured to have the size of 20 GB.

Final network manifest

Let's put the pieces together. See the final network manifest below.

apiVersion: streams.network.edgefarm.io/v1alpha1
kind: Network
metadata:
  name: mynetwork
  namespace: mynamespace
spec:
  parameters:
    users:
      - name: "app1"
        limits:
            payload: -1
            data: -1
            subscriptions: -1
        permissions:
          pub:
            allow:
              - "topic1.>"
              - "a.b.*.c.>"
            deny: []
          sub:
            allow: []
            deny: []
      - name: "app2"
        limits:
            payload: -1
            data: -1
            subscriptions: -1
        permissions:
          pub:
            allow:
              - "topic3"
            deny: []
          sub:
            allow:
              - "topic1.>"
              - "a.b.*.c.>"
            deny: []
      - name: "external-access"
        limits:
            payload: -1
            data: -1
            subscriptions: -1
        permissions:
          sub:
            allow:
              - "topic3"
            deny: []
          pub:
            allow: []
            deny: []
        writeToSecret:
          name: external-access-creds

    subNetworks:
      - name: small
        limits:
          fileStorage: 100M
          inMemoryStorage: 10M
        nodepoolSelector:
          matchLabels:
            app1/network: small
      - name: big
        limits:
          fileStorage: 1G
          inMemoryStorage: 10M
        nodepoolSelector:
          matchLabels:
            app1/network: big

    streams:
      - name: app-stream-small #(1)!
        type: Standard
        subNetworkRef: small
        config:
          subjects:
            - topic1.>
            - a.b.*.c.>
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 100000000 # 100MB

      - name: app-stream-big #(2)!
        type: Standard
        subNetworkRef: big
        config:
          subjects:
            - topic1.>
            - a.b.*.c.>
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 10000000000 # 10GB

      - name: results-stream-small #(3)!
        type: Standard
        subNetworkRef: small
        config:
          subjects:
            - topic3
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 2000000 # 200MB

      - name: results-stream-big #(4)!
        type: Standard
        subNetworkRef: big
        config:
          subjects:
            - topic3
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 2000000 # 200MB

      - name: aggregate-stream #(5)!
        type: Aggregate
        references:
          - results-stream-small
          - results-stream-big
        config:
          retention: Limits
          discard: Old
          maxConsumers: -1
          maxMsgs: -1
          storage: File
          maxBytes: 20000000000 # 20GB

Connect the applications to the network

Now that the network is created, the applications can be connected to the network. This is done by defining an edgefarm.applications definition and using the special edgefarm-network trait.

This is an example how the manifests look like for app1 and app2.

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: app1
  namespace: mynamespace
spec:
  components: #(1)!
    - name: app1-small
      type: edgefarm-applications
      properties:
        name: app1
        image: docker.io/myapp/app1:1.0.0
        nodepoolSelector:
          matchLabels:
            app1/network: small
      traits:
        - type: edgefarm-network
          properties:
            network:
              name: mynetwork 
              subnetwork: small #(2)!
              user: app1
    - name: app1-big
      type: edgefarm-applications
      properties:
        name: app1
        image: docker.io/myapp/app1:1.0.0
        nodepoolSelector:
          matchLabels:
            app1/network: big
      traits:
        - type: edgefarm-network
          properties:
            network:
              name: mynetwork 
              subnetwork: big #(3)!
              user: app1
  1. We define two components representing app1 in different subnetworks. Both components connect to the same network using the same user credentials but on different subnetworks. This way, both components running on different types of Edge Nodes can behave the same.
  2. The app1-small component connects to the small subnetwork.
  3. The app1-big component connects to the big subnetwork.

The Application manifest for app2 looks pretty similar to the one for app1.

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: app2
  namespace: mynamespace
spec:
  components:
    - name: app2-small
      type: edgefarm-applications
      properties:
        name: app2
        image: docker.io/myapp/app2:1.0.0
        nodepoolSelector:
          matchLabels:
            app1/network: small
      traits:
        - type: edgefarm-network
          properties:
            network:
              name: mynetwork 
              subnetwork: small
              user: app2
    - name: app2-big
      type: edgefarm-applications
      properties:
        name: app2
        image: docker.io/myapp/app2:1.0.0
        nodepoolSelector:
          matchLabels:
            app1/network: big
      traits:
        - type: edgefarm-network
          properties:
            network:
              name: mynetwork 
              subnetwork: big
              user: app2

Connect external applications to the network

To connect external applications to the network, the user external-access can be used. The credentials for this user are stored in a Kubernetes secret. To read the creds file for this user, use the following command:

$ kubectl get secrets -n mynamespace external-access-creds -o jsonpath='{.data.creds}' | base64 -d
-----BEGIN NATS USER JWT-----
eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJZVFNMWFhaT1hVUkkyQk9NWlc1N0hYUEg3UUozRE5MMklOV1VHSEdaV0xQR0NBUzNKQVBRIiwiaWF0IjoxNzAyNjM4MDY4LCJpc3MiOiJBQzNDSFhCNlJWT1hMR0ZIVEFIWEFFU1BBVkVOR1E2NjRXTk9aSEVGQ0tJUURMVkNJSTczVEVZTiIsInN1YiI6IlVEVkxVUE1TQzJPVExUMktEUU82VjRRSFZTWFZDWkpNNDJJVVY0NzJVQjdXRTRDQk8yUFZXVVhMIiwibmF0cyI6eyJwdWIiOnt9LCJzdWIiOnsiYWxsb3ciOlsidG9waWMzIiwiX0lOQk9YLlx1MDAzZSJdfSwic3VicyI6LTEsImRhdGEiOi0xLCJwYXlsb2FkIjotMSwidHlwZSI6InVzZXIiLCJ2ZXJzaW9uIjoyfX0.tXFgmL1J_uJYqbi2bCi-f9htJSPw8Jiv1n5NCsib8yZ4UwUFIwNuViBu4AlMDDaT4z2c73UH_M-o-b03Uu0CBw
------END NATS USER JWT------

************************* IMPORTANT *************************
NKEY Seed printed below can be used to sign and prove identity.
NKEYs are sensitive and should be treated as secrets.

-----BEGIN USER NKEY SEED-----
SUANAEIEIUD5ZOOE2P63QQKKOOC3A32JVY4X2IEV2S5AXATXVY7LDHSCWM
------END USER NKEY SEED------

*************************************************************

As edgefarm.network uses NATS.io as the underlying messaging system, the credentials are in the form of a JWT token and a NKEY seed. The JWT token is used to authenticate the user while the NKEY seed is used to prove idendity.

nats --server <the NATS server address> --creds <your creds file> <command>