---
# System prepended metadata

title: 'Metal Demo fodder (deployments, compositions)'

---

## Have you Ever?
Has this happened to you?

"Man, Equinix Metal is cool, but I just wish I could push a button and deploy an application!"

Maybe you've tried containers? Or perhaps you've attempted to install kuberenetes?

*User clicks on kubernetes logo, gets error message*

Or maybe even service mesh? 

*user clicks on istio icon and gets complicated deployment graphic, screams and gets sledge hammer*

Does it feel like things are harder than they have to be?

*User crying on floor*
"There's got to be a better way!"
*rocks back and forth

Well now there is!

Introducing the Equinix App Market!

With Patented One Click Technology!

Now applications deploy like Equinix Metal servers--in minutes!

Kubernetes!

Click...show sped up deployment flow. End with node list and "Ahhs"

Wordpress!

Databases!

Crypto Miners!

Elastic Search!

GitOps!

Grafana!

Harbor!

RabbitMQ!

Docker!

Prometheus!

MySQL!

All these and more can be yours for the low low price of *FREE!*

Act now and get a free gift...a Minecraft server!

Operators are standing by, come to https://metal.equinix.com/appmarket and get your clickops on today!

*offer not valid in Wyoming and parts of New Mexico. Web apps shown may be closer than they appear. Crypto currency past performance is not indicative of future gains. Docker has a whale for a logo. Terms and conditions apply.

CALL TODAY!

## Create Cluster

### Install Brew
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

### Install Tools
```
brew upgrade
brew install kind
brew install kubectl
brew install helm
```

### Create Cluster

```sh
kind create cluster 
```
<!-- don't need this: --image kindest/node:v1.23.0 --wait 5m -->

## Install Crossplane

```
kubectl create namespace crossplane-system

helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update

helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
```

## Install Crossplane CLI

```
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
```

## Provider


```sh
kubectl crossplane install provider crossplane/provider-jet-equinix:v0.2.0
```

Wait for the provider to be Installed and Healthy
```
kubectl get provider
```

Alternatively:

https://github.com/crossplane-contrib/provider-jet-equinix/blob/main/examples/install.yaml

#### Configure Secret

Update credentials and install:

https://github.com/crossplane-contrib/provider-jet-equinix/blob/main/examples/providerconfig/secret.yaml.tmpl

```sh
eval $(metal env)
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: example-creds
  namespace: crossplane-system
type: Opaque
stringData:
  credentials: |
    {
      "client_id": "PlaceYour32CharacterClientIDHere",
      "client_secret": "t0ps3cr3t11",
      "auth_token": "$METAL_AUTH_TOKEN",
      "request_timeout": "30",
      "response_max_page_size": "100",
      "endpoint": "https://api.equinix.com"
    }
EOF
```

#### Configure Provider

```sh
cat << EOF | kubectl apply -f -
---
apiVersion: equinix.jet.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
  name: default
spec:
  credentials:
    source: Secret
    secretRef:
      name: example-creds
      namespace: crossplane-system
      key: credentials
---
EOF
```

## Create Compositions

Install the demo compositions.

**See <https://github.com/crossplane-contrib/provider-jet-equinix/pull/12/files#r985311946> (or the merged files) for the latest.**

For more information about Composition:
* <https://crossplane.io/docs/v1.9/concepts/composition.html>
* <https://crossplane.io/docs/v1.9/reference/composition.html>

For more information about the Equinix resources:
* `kubectl api-resources | grep equinix`
* `kubectl explain devices.metal.equinix.jet.crossplane.io/v1alpha1.spec.forProvider`
* <https://doc.crds.dev/github.com/crossplane-contrib/provider-jet-equinix>


C:
args:
  - k3stoken
  - metro
resources:
    Proj
    - create a secret that is userdata + k3stoken
    DevCP
    - userdatasecretref: ^
    - want to create a userdata secret for agents to use
    - createConnectionSecret:
       fmt with userdata + k3stoken + server ip
    DevDP
    - userdatasecretref: ^



(see the pull request linked above for the latest yaml)
```sh
kubectl apply -f - << EOF
---
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: k3sclusters.deployments.equinix.com
spec:
  writeConnectionSecretsToNamespace: crossplane-system
  compositeTypeRef:
    apiVersion: deployments.equinix.com/v1alpha1
    kind: K3sCluster
  resources:
    - name: k3s-server
      base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: Device
        metadata:
          labels:
            k3s-server: 'true'
        spec:
          forProvider:
            hostname: k3s-server
            plan: c3.small.x86
            operatingSystem: ubuntu_20_04
            billingCycle: hourly
            locked: false
            networkType: hybrid
            tags:
            - crossplane
          writeConnectionSecretToRef:
            name: server
            namespace: crossplane-system
          reclaimPolicy: Delete
      patches:
        - type: ToCompositeFieldPath
          fromFieldPath: status.atProvider.accessPublicIpv4
          toFieldPath: status.serverIP
        - type: FromCompositeFieldPath
          fromFieldPath: spec.metro
          toFieldPath: spec.forProvider.metro
        - type: CombineFromComposite
          toFieldPath: spec.forProvider.userdata
          combine:
            variables:
              - fromFieldPath: spec.k3stoken
            strategy: string
            string:
              fmt: |
                #cloud-config
                write_files:
                #- permissions: '0660'
                #  path: /etc/rancher/k3s/config.yaml
                #  content: |
                #    # k3s config  
                runcmd:
                - sudo apt update
                - sudo apt upgrade -y
                - curl -sfL https://get.k3s.io | \
                  INSTALL_K3S_EXEC="server" \
                  K3S_TOKEN=%s sh -
    - name: k3s-agent
      base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: Device
        metadata:
          labels:
            k3s-agent: 'true'
        spec:
          forProvider:
            hostname: k3s-agent
            plan: c3.small.x86
            operatingSystem: ubuntu_20_04
            billingCycle: hourly
            locked: false
            networkType: hybrid
            tags:
            - crossplane
          writeConnectionSecretToRef:
            name: crossplane-conformance
            namespace: crossplane-system
          reclaimPolicy: Delete
      patches:
        # TODO we reuse metro patches. create a 'patchtype'
        - type: FromCompositeFieldPath
          fromFieldPath: spec.metro
          toFieldPath: spec.forProvider.metro
        - type: CombineFromComposite
          toFieldPath: spec.forProvider.userdata
          policy:
            fromFieldPath: Required
          combine:
            variables:
              - fromFieldPath: spec.k3stoken
              - fromFieldPath: status.serverIP
              # TODO how to get server address?
            strategy: string
            string:
              fmt: |
                #cloud-config
                write_files:
                #- permissions: '0660'
                #  path: /etc/rancher/k3s/config.yaml
                #  content: |
                #    # k3s config  
                runcmd:
                - sudo apt update
                - sudo apt upgrade -y
                - curl -sfL https://get.k3s.io | \
                  K3S_TOKEN=%s \
                  K3S_URL=https://%s:6443 sh -
---
EOF
```

```sh
kubectl apply -f - << EOF
---
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: k3sclusters.deployments.equinix.com
spec:
  group: deployments.equinix.com
  names:
    kind: K3sCluster
    listKind: K3sClusterList
    plural: k3sclusters
    singular: k3scluster
  versions:
    - name: v1alpha1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          description: Managed resources for provider-jet-equinix crossplane K3s Cluster
          type: object
          properties:
            spec:
              type: object
              properties:
                metro:
                  type: string
                  description: metro
                k3stoken:
                  type: string
                  description: K3s Token
              required:
                - metro
                - k3stoken
            status:
              type: object
              properties:
                serverIP:
                  type: string
                  description: IPv4 of the K3s Server
---
EOF
```

### Instances of Compositions

Try out the compositions with custom values

```sh
kubectl apply -f - << EOF
---
apiVersion: deployments.equinix.com/v1alpha1
kind: K3sCluster
metadata:
  name: sv-k3s
spec:
  metro: sv
  k3stoken: topsecret
---
EOF
```

#### Unused Misc Notes


```sh
kubectl apply -f - <<<EOS
...
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: demoapp.apps.acme.com
spec:
  writeConnectionSecretsToNamespace: crossplane-system
  compositeTypeRef:
    apiVersion: apps.acme.com/v1alpha1
    kind: Demoapp
  resources:
    - base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: Project
        spec:
         forProvider:
           name: demoapp-crossplane
         providerConfigRef:
           name: default
    - base:
        apiVersion: metal.equinix.jet.crossplane.io/v1alpha1
        kind: Device
        spec:
          forProvider:
            hostname: demoapp-crossplane
            plan: c3.small.x86
            operatingSystem: ubuntu_20_04
            billingCycle: hourly
            locked: false
            networkType: hybrid
            tags:
            - crossplane
          providerConfigRef:
            name: equinix-metal-provider
          writeConnectionSecretToRef:
            name: crossplane-conformance
            namespace: crossplane-system
          projectIdRef:
            matchControllerRef: true
      patches:
        - fromFieldPath: spec.metro
          toFieldPath: spec.forProvider.metro
    - base:
        apiVersion: vlan.metal.equinix.com/v1alpha1
        kind: VirtualNetwork
        spec:
          forProvider:
            description: conformance provisioned VLAN
          providerConfigRef:
            name: equinix-metal-provider
      patches:
        - fromFieldPath: spec.metro
          toFieldPath: spec.forProvider.metro
    - base:
        apiVersion: ports.metal.equinix.com/v1alpha1
        kind: Assignment
        spec:
          forProvider:
            deviceIdSelector:
              matchControllerRef: true
            virtualNetworkIdSelector:
              matchControllerRef: true
            name: eth1
          providerConfigRef:
            name: equinix-metal-provider
EOS
```