Code Monkey home page Code Monkey logo

provider-equinix-metal's Introduction

Crossplane Equinix Metal Provider

GitHub release crds.dev Go Report Card Slack Twitter Follow

Overview

From Crossplane's Provider documentation:

Providers extend Crossplane to enable infrastructure resource provisioning. In order to provision a resource, a Custom Resource Definition (CRD) needs to be registered in your Kubernetes cluster and its controller should be watching the Custom Resources those CRDs define. Provider packages contain many Custom Resource Definitions and their controllers.

This is the Crossplane Provider package for Equinix Metal infrastructure. The provider that is built from this repository can be installed into a Crossplane control plane.

This repository is Maintained meaning that this software is supported by Equinix Metal and its community - available to use in production environments.

Getting Started and Documentation

For getting started guides, installation, deployment, and administration, see the Crossplane Documentation.

Pre-requisites

  • Kubernetes cluster
    • For example Minikube, minimum version v0.28+
  • Helm, minimum version v3.0.0+.

Installing Crossplane

For the most up to date, detailed, instructions, check Crossplane's documentation.

The following instructions are provided for convenience.

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 --version 1.2.2

Install the Crossplane CLI

Fetch the CLI and follow the commands provided in the output:

$ curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
kubectl plugin downloaded successfully! Run the following commands to finish installing it:

sudo mv kubectl-crossplane $HOME/.local/bin
kubectl crossplane --help

Visit https://crossplane.io to get started. ๐Ÿš€
Have a nice day! ๐Ÿ‘‹
sudo mv kubectl-crossplane $HOME/.local/bin

Install the Equinix Metal Provider

For the most up to date version and install notes, see https://cloud.upbound.io/registry/equinix/provider-equinix-metal.

kubectl crossplane install provider registry.upbound.io/equinix/provider-equinix-metal:v0.0.7

After the package has been fetched and installed, you should see that the provider package is ready:

kubectl get provider -o wide
NAME                             INSTALLED   HEALTHY   PACKAGE                                                     AGE
equinix-provider-equinix-metal   True        True      registry.upbound.io/equinix/provider-equinix-metal:v0.0.7   76m

Create a Provider Secret

Create a Equinix Metal Project and a project level API key.

The following commands will require your Equinix Metal API key and a project ID. Enter your API key and project ID when prompted:

read -s -p "API Key: " APIKEY; echo
read -p "Project ID: " PROJECT_ID; echo

(The read command may need to be modified for shells other than bash.)

Create a Kubernetes secret called metal-creds with the API Key and Project ID stored as JSON in a key called credentials.

kubectl create -n crossplane-system secret generic --from-file=credentials=<(echo '{"apiKey":"'$APIKEY'", "projectID":"'$PROJECT_ID'"}') metal-creds

The secret name and key name are configurable. Whatever names you choose must match the settings in the ProviderConfig below.

Create a Provider Config record

Get the project id from the Equinix Metal Portal or using the Equinix Metal CLI (packet project get). With PROJECT_ID in your environment, run the command below:

cat << EOS | kubectl apply -f -
apiVersion: metal.equinix.com/v1beta1
kind: ProviderConfig
metadata:
  name: equinix-metal-provider
spec:
  projectID: $PROJECT_ID
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: metal-creds
      key: credentials
EOS

TIP: If the ProviderConfig is given the special name "default", Equinix Metal Crossplane resources will choose this configuration making the providerConfigRef field optional.

Provision an Equinix Metal Device

Save the following as device.yaml:

apiVersion: server.metal.equinix.com/v1alpha2
kind: Device
metadata:
  name: crossplane-example
spec:
  forProvider:
    hostname: crossplane-example
    plan: c3.small.x86
    metro: sv
    operatingSystem: ubuntu_20_04
    billingCycle: hourly
    locked: false
    networkType: hybrid
    tags:
    - crossplane
  providerConfigRef:
    name: equinix-metal-provider
  writeConnectionSecretToRef:
    name: crossplane-example
    namespace: crossplane-system
  reclaimPolicy: Delete

Create the resource:

$ kubectl create -f device.yaml
device.server.metal.equinix.com/devices created

To view the device and other Equinix Metal resources in the cluster:

$ kubectl get equinix -o wide
kubectl get provider
NAME                             INSTALLED   HEALTHY   PACKAGE                                                     AGE
equinix-provider-equinix-metal   True        True      registry.upbound.io/equinix/provider-equinix-metal:v0.0.7   73m

NAME                                                 READY   SYNCED   STATE    ID                                     HOSTNAME             FACILITY   IPV4             RECLAIM-POLICY   AGE
device.server.metal.equinix.com/crossplane-example   True    True     active   d81d643a-998f-4203-a667-7f9378481b1d   crossplane-example   sv15       139.178.68.111                    53m

NAME                                                                         AGE   CONFIG-NAME              RESOURCE-KIND    RESOURCE-NAME
providerconfigusage.metal.equinix.com/0a280921-1f3a-48ad-adb2-15ed8e6146f1   53m   equinix-metal-provider   Device           crossplane-example

NAME                                                      AGE   SECRET-NAME
providerconfig.metal.equinix.com/equinix-metal-provider   69m   

SSH Connection credentials (including IP address, username, and password) can be found in the provider managed secret defined by writeConnectionSecretToRef.

Caution - Secret data is Base64 encoded, access to the namespace where this secret is stored offers root access to the provisioned device.

$ kubectl get secret -n crossplane-system crossplane-example -o jsonpath='{.data}'; echo
map[endpoint:MTM5LjE3OC44OC41Nw== password:cGFzc3dvcmQ== port:MjI= username:cm9vdA==]

To delete the device:

$ kubectl delete -f device.yaml
device.server.metal.equinix.com/devices deleted

Roadmap and Stability

This Crossplane provider is alpha quality and not intended for production use.

Equinix Metal devices, virtual networks, and ports can be managed through this provider, which provides basic integration. Advanced features like BGP, VPN, Volumes are not currently planned. If you are interested in these features, please let us know by opening issues and reaching out.

See https://github.com/packethost/crossplane-provider-equinix-metal/milestones for project milestones.

Contributing

crossplane-provider-equinix-metal is a community driven project and we welcome contributions. See the Crossplane Contributing guidelines to get started.

Report a Bug

For filing bugs, suggesting improvements, or requesting new features, please open an issue.

Contact

Please use the following Slack channels to reach members of the community:

provider-equinix-metal's People

Contributors

displague avatar hasheddan avatar jasmingacic avatar rainleander avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

provider-equinix-metal's Issues

Investigate generating this client

What problem are you facing?

New resources will take developer time to research and implement, creating a delay between provider innovations and the user's ability to consume new features and services.

How could the Equinix Metal Crossplane Provider help solve your problem?

By generating the client, or portions thereof, delivery time should be reduced.

This issue is similar in spirit to equinixmetal-archive/packngo#215 and any pitfalls or revelations on that issue may impact or enable this issue.

Implement Metros

Equinix Metal resources (Devices, VLANs, IPReservations, SpotMarketRequests, Batches) accept a new metro field.

Use of the field conflicts with the facility field at spec time. One of facility or metro must be provided for these resources at create time.

Regardless of how the resource was created, facility will be included in the response and subsequent fetches. metro may only be included in the response if the resource was created with a metro parameter, but this differs between resources depending on how that resource type operates at a metro level.

  • Update packngo to 0.9.0+ (0.10.0 will be needed for vlan.vxlan support).
  • Add support for Metros to device resources
  • Add support for Metros to vlan resources

Implement Project resources

What problem are you facing?

Equinix Metal offers Projects to confine Devices, IP ranges, and additional resources. These resources can not be managed through this provider.

How could the Equinix Metal Crossplane Provider help solve your problem?

Implement Projects.

The Provider resource currently depends on a default Project ID. It may feel awkward to manage one Project with the context of another context.
Should we consider using the Organization ID instead of the Project ID in the Provider resource? If we do, we would need to reintroduce ProjectID as a Device and VirtualNetwork parameter.

Add support for VirtualNetwork

What problem are you facing?

crossplane-provider-packet does not currently support provisioning virtual networks on Packet.

How could the Packet Crossplane Provider help solve your problem?

Add v1alpha1 support for VirtualNetwork in the vlan.packet.crossplane.io group.

Add support for Port Assignment

What problem are you facing?

crossplane-provider-packet does not currently have support for assigning ports to virtual networks

How could the Packet Crossplane Provider help solve your problem?

Add v1alpha1 support for Assignment in ports.packet.crossplane.io group.

Establish build / publish pipeline

The tooling in this repo is configured for a crossplaneio stack release, which is opinionated about using tools such as Jenkins and Sonar. It will need to be updated with any testing / publishing tools that are suitable for Packet.

cc @jmarhee @jasmingacic

Reusing connection secret reference causes errors

What happened?

Created a second device with the same credential secret as an existing device.

When deleting the first device, errors reported that the UID of the secret did not match the first resource. The deletion failed.

How can we reproduce it?

What environment did it happen in?

Crossplane version:

Implement Spot Market Requests

What problem are you facing?

Equinix Metal offers Spot Market Requests to provision pools of devices with pricing constraints. These are not made available through this provider.

How could the Equinix Metal Crossplane Provider help solve your problem?

Implement Spot Market Requests.

Depends on equinixmetal-archive/packngo#228 (more context there)

Implement IP Reservation Requests

What problem are you facing?

It is not yet possible to create IP reservations (EIPs) using Crossplane.

Some use cases for EIPs:

How could the Equinix Metal Crossplane Provider help solve your problem?

Packet Uniform Standards Request: Maintained Repo

What problem are you facing?

Packet maintains a number of public repositories that help customers to run various workloads on Packet. These repositories are in various states of completeness and quality, and being public, developers often find them and start using them. This creates problems:

  • Developers using low-quality repositories may infer that Packet generally provides a low quality experience.
  • Many of our repositories are put online with no formal communication with, or training for, customer success. This leads to a below average support experience when things do go wrong.
  • We spend a huge amount of time supporting users through various channels when with better upfront planning, documentation and testing much of this support work could be eliminated.

To that end, we propose three tiers of repositories: Private, Experimental, and Maintained.

As a resource and example of a maintained repository, we've created https://github.com/packethost/standards. This is also where you can file any requests for assistance or modification of scope.

The Goal

Our repositories should be the example from which adjacent, competing, projects look for inspiration.

Each repository should not look entirely different from other repositories in the ecosystem, having a different layout, a different testing model, or a different logging model, for example, without reason or recommendation from the subject matter experts from the community.

We should share our improvements with each ecosystem while seeking and respecting the feedback of these communities.

Whether or not strict guidelines have been provided for the project type, our repositories should ensure that the same components are offered across the board. How these components are provided may vary, based on the conventions of the project type. GitHub provides general guidance on this which they have integrated into their user experience.

How could the Packet Crossplane Provider help solve your problem?

We believe this repository is Maintained and therefore needs the following files updated:

If you feel the repository should be experimental or end of life or that you'll need assistance to update these files, please let us know by filing an issue with https://github.com/packethost/standards.

"Failed to Provision" devices are not detected properly

What happened?

When a device fails to provision, the Equinix Metal backend will remove that device from the account. The device is moved away for EM to investigate the bare metal provisioning failure.

For a client like Crossplane, observation requests to the device will fail. These failures will not be 404s, as we currently expect. These failures will be 403s, which makes some sense since the device exists but is not accessible to us.

I do not know if this behavior differs between on-demand and reservered instances.

https://github.com/packethost/crossplane-provider-equinix-metal/blob/master/pkg/controller/server/device/managed.go#L131 should be updated to check for 403 responses. 403 responses should be handled in the same way a 404 is handled. The machine was deleted or does not otherwise exist, or could not be created successfully; make a new device.

How can we reproduce it?

Hard to reproduce because hardware or the provisioning process must fail.

What environment did it happen in?

Crossplane version: 0.14
EM version: 0.0.5

Update stack-packet to be compatible with Crossplane v0.4.0

Crossplane v0.4.0 introduced a number of breaking changes including:

  • Removal of portable resource classes [1]
  • Moving all managed resources and resource classes to cluster-scoped [1]
  • Introduction of claim scheduling controller and claim defaulting controllers [1]
  • Introduction of forProvider / atProvider paradigm (not breaking) [2]
  • Cross-resource references (not breaking, not applicable until reliant resources exist in this stack) [3]

The design of these components is reflected in the following docs:
[1] https://github.com/crossplaneio/crossplane/blob/master/design/one-pager-simple-class-selection.md
[2] https://github.com/crossplaneio/crossplane/blob/master/design/one-pager-managed-resource-api-design.md
[3] https://github.com/crossplaneio/crossplane/blob/master/design/one-pager-cross-resource-referencing.md

stack-packet should be updated to be compatible with these changes.

Prepare for Crossplane Certification

What problem are you facing?

This provider should become a Crossplane Certified provider:

How could the Equinix Metal Crossplane Provider help solve your problem?

  • Update the Provider to Crossplane 1.2
  • Implement an XRD?
  • ... (check for any other details not yet added to the conformance guidelines)

VLAN Assignments do not handle 422 when already assigned

What happened?

A VLAN assignment failed to reach ready/sync after successfully configured the external resource. The provider returns a 422 on subsequent requests to create the VLAN assignment.

$ kubectl describe assignments.ports.metal.equinix.com 
...
Events:
  Type     Reason                        Age                From                                        Message
  ----     ------                        ----               ----                                        -------
  Warning  CannotCreateExternalResource  17m (x9 over 83m)  managed/assignment.ports.metal.equinix.com  cannot create Assignment: POST https://api.equinix.com/metal/v1/ports/64369d8b-fbb8-410b-b38b-aab054f7ff2c/assign: 422 Virtual network 1182 already assigned

These 422 errors should be handled (or the provider or packngo should handle this condition differently equinixmetal-archive/packngo#187.

How can we reproduce it?

Deploy the Device + VLAN + Attachment examples (#60) and kill the provider pod before ready state is reached.

What environment did it happen in?

Crossplane version:
XP 1.2 / EM v0.7.0

Update to packngo 0.5.0

What problem are you facing?

The latest packngo version, 0.5.0, includes API backend and Go binding changes.

The backend API:

  • URL is changed to api.equinix.com/metal/v1
  • device, vlan, attachment href values will include additional components (/metal/v1) in the URL path

The bindings have:

  • changed the NetworkType detection and setting
  • added a force detach volumes parameter to Device Delete

How could the Equinix Metal Crossplane Provider help solve your problem?

stack-packet docker image not published to docker hub under crossplane

Deploying the below yaml doesn't currently work as it tries to create a pod that tries to pull the non-existent image docker.io/crossplane/stack-packet:latest

apiVersion: stacks.crossplane.io/v1alpha1
kind: ClusterStackInstall
metadata:
  name: "crossplane-stack-packet"
spec:
  package: "crossplane/stack-packet"

Can someone build and push that image?

customdata and userdata should agree on casing

What happened?

I tried to provision a device with the following parameters:

forProvider:
  userdata: |
     ...
  customdata: |
     ...

This failed to provision and I spent a while scratching my head wondering if the client was wired up correctly.
I did not receive an error when updating the resource to include this parameter, but it was eventually removed in a subsequent reconciliation.

I discovered that customData was the name that was correct and accepted.

It is confusing that userdata and customData do not follow the same standard.

Pick one.

Without knowing why the wrong case was accepted and later removed from the resource, users may attempt to use userdata or userData (similar for customdata) and experience the same problem. Should this change have been rejected earlier?

How can we reproduce it?

Use customdata in a device spec.

What environment did it happen in?

Crossplane version: v0.14
EM Provider: v0.0.5

Add ability to use ConfigMap to define Device UserData and CustomData

Device UserData and CustomData are lengthy fields that can benefit from reuse. Additionally, other Crossplane providers (provider-cloudinit), compositions, or other operators may manage the ConfigMap resources providing flexibility.

Is there a conventional format for spec.ForProvider fields that take can accept a configmap source?

The existing format is:

spec:
  forProvider:
    userdata: |
    ...

How should userdata from configmap be specified? Should this be presented as a new field?

spec:
  forProvider:
    userdataConfigMapRef:
      name: foo
      namespace: foo
      key: foo
      optional: false

Is it possible or recommended to have an alternate userdata syntax (alternate to the existing string format)?

spec:
  forProvider:
    userdata:
      valueFrom:
        kind: ConfigMap # should ConfigMap be the only resource-type? I think that's fair.
        name: foo
        namespace: foo
        key: foo
        optional: false

What pattern should be adopted for watching the specified ConfigMaps for changes?
Are additional fields needed to permit a redeploy behavior on ConfigMap changes? Would this behavior conflict with the existing immutable field experience? You can not change facility, but should that be the case? What should happen if ConfigMap is changed?

The Equinix Metal API allows for changes to the Userdata and Customdata fields after deployment. This does not trigger a rebuild on the EM side. The new values can be accessed from the metadata service. These fields have utility beyond boot time.

Immutable Infrastructure

Should the Device resource take a parameter (within spec, not forProvider) that defines the behavior to take? destroy OnUserdataChange: true? Would similar fields be needed for immutable parameters like facility which can not be updated in the EM API or would changes to these fields dictate a delete+create cycle?

Network types is now bond instead of device scoped

What problem are you facing?

Network types (hybrid, layer2-bonded, layer2-individual, layer3) have always been a computed value used by the Terraform provider and Equinix Metal UI to represent a complex arrangement of port bindings, layer-2 or layer-3 readiness, management address assignments, and vlan attachments.

With recent API and product enhancements, affording more customization of the port configuration, the device-wide single word network type is no longer relevant. This is especially the case for four-port devices, such as n2.x-large (with larger sizes inevitable) where there are multiple bonding pairs. The notion of a bonding pair (with only 2 ports) may also lead to inaccurate representation.

At first glance, it would seem that the scope has shifted to a bond (ethernet pairing) scope. This is not entirely correct and will become less correct in time.

EM offers direct port modification APIs that offer similar functionality regardless of whether the port being affected is a bonding port or an ethernet port.

The most expressive and accurate way to represent port state configuration to users is directly, without a concocted network type that pulls various levers and switches when toggled.

How could the Equinix Metal Crossplane Provider help solve your problem?

A more expressive way to configure the device networking would allow for all ports to be managed independently, with Kubernetes eventually reconciling all of the port states. Ports can be acted on independently of any device or hardware reservation, however, all ports available through the API currently represent either a bonding or ethernet port attached to a user-owned hardware reservation or device instance.

I believe we can reasonably restrict port actions to the scope of a device and do not need independent resources to manage ports. Managing ports independently may be more complicated based on the need to reference the device of the port or the id of the port. On the contrary, in the scope of a device, the port can be referenced easily by a well known, and API guaranteed port name.

I roughly propose the following forProvider spec representation of ports:

forProvider:
  plan: "n2.x-large"
  ports: # network_ports in the API naming
    bond0: # always comprised of ports eth0+eth1 on 2 port devices, or eth0+eth2 on 4 port devices
      bonded: true # default
      layer2: false # this is default on new devices. changes result in /ports/id/convert/layer-[2|3] API calls
      vlans: [1234, 5678, 1234] # shortened this from the API "virtual_networks"
      native_vlan: 5678 # optional, must be one of the above if set
      ip_addresses:
      - reservation_id: uuid # reserved addresses by uuid, may include global ips
      - cidr_notation: "1.2.3.4/24" # reserved addresses by address, may include global ips
      - type: private_ipv4 # dynamically assigned addresses, available via metadata.platformequinix.net
        cidr: 30 
    bond1: # comprised of port eth1+eth3 on 4 port devices
      bonded: false
    eth1: # unbonded eth ports can use most of the same attributes bond ports can use
      layer2: true
      vlans: [7654]
    eth3:
      layer2: true
      vlans: [9876]

The atProvider status would include the MAC address, network type (as reported by the API), and id of each port (among other things).

This is related to the following discussions:

Update to v2 Crossplane packging format

What problem are you facing?

Crossplane v0.13 introduced a new package manager and dropped support for the old package manager. As part of this change, a new v2 package format was introduced. Old provider packages that do not conform will be unable to be installed with Crossplane v0.13 or later.

How could the Packet Crossplane Provider help solve your problem?

Update to v2 package format as described in crossplane/crossplane#1756 and the linked PRs.

Update tooling URLs to packethost org

There are a number of places in the build tooling that use github.com/hasheddan/stack-packet as the repo URL (i.e. here). This should be updated to github.com/packethost/stack-packet.

port does not exist when delete attachment

What happened?

A metal device was deleted before the VLAN Attachment resource was deleted. This resulted in 404s when looking up the device port. If this is ever encountered, it means that the port is no longer in use. We can treat this as a successful port/vlan unassignment.

Here's an example snippet of how the 404 case is handled today:

Status:
  Conditions:
    Last Transition Time:  2021-06-14T19:47:45Z
    Message:               observe failed: port does not exist
    Reason:                ReconcileError
    Status:                False
    Type:                  Synced
    Last Transition Time:  2021-06-14T19:16:30Z
    Reason:                Deleting
    Status:                False
    Type:                  Ready
Events:
  Type     Reason                           Age                 From                                        Message
  ----     ------                           ----                ----                                        -------
  Warning  CannotObserveExternalResource    7s (x15 over 90s)   managed/assignment.ports.metal.equinix.com  port does not exist

A similar situation may be encountered if the port has been reassigned to a different user, in which case a 403 may be returned.

How can we reproduce it?

  • Create a device in the EM Portal UI.
  • Create a VLAN in the Portal UI.
  • Create a VLAN attachment resource in Crossplane.
  • Delete the UI created components.

What environment did it happen in?

Crossplane version: 1.22
EM Provider: 0.0.8

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.