Skip to content

Commit

Permalink
Merge pull request #186 from alces-flight/feature/network-devices
Browse files Browse the repository at this point in the history
Add representation of network devices
  • Loading branch information
jamesremuscat authored Feb 23, 2024
2 parents aef9474 + 31a7812 commit 887565b
Show file tree
Hide file tree
Showing 25 changed files with 458 additions and 22 deletions.
1 change: 0 additions & 1 deletion app/controllers/api/v1/devices_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ def details_params
:login_user,
:volume_details
)
legacy_params[:type] = 'Device::ComputeDetails'
return legacy_params
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/api/v1/templates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ def destroy

private

CREATE_ONLY_PARAMS = %w(height version schema_version)
PERMITTED_PARAMS = %w(name description foreign_id vcpus ram disk)
CREATE_ONLY_PARAMS = %w(height version schema_version tag)
PERMITTED_PARAMS = %w(name description foreign_id vcpus ram disk) << { images: ['front', 'rear'] }
def template_params
params.require(:template).permit(*PERMITTED_PARAMS, *CREATE_ONLY_PARAMS)
end
Expand Down
15 changes: 15 additions & 0 deletions app/models/device/network_details.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Device::NetworkDetails < Device::Details

validate :device_uses_network_template

private

def device_uses_network_template
reload_device
return unless device.present?
unless device.template.tag == 'network'
self.errors.add(:device, 'must use the `network` template if it has a Device::NetworkDetails')
end
end

end
13 changes: 5 additions & 8 deletions app/models/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ class Template < ApplicationRecord
validates :rack_repeat_ratio,
length: { maximum: 255 }

# Allow a single default rack template.
validates :default_rack_template,
inclusion: { in: [true, false] }
validates :default_rack_template,
uniqueness: true,
if: :default_rack_template

# The following attributes have different validations depending on whether
# this is a template for a rack or a device.
validates :rows,
Expand Down Expand Up @@ -102,14 +95,18 @@ class Template < ApplicationRecord
numericality: { only_integer: true, greater_than: 0 },
allow_nil: true

validates :tag,
uniqueness: true,
if: :tag

####################################
#
# Class Methods
#
####################################

def self.default_rack_template
find_by(default_rack_template: true)
find_by_tag('rack')
end

#######################
Expand Down
2 changes: 2 additions & 0 deletions app/presenters/device/network_details_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Device::NetworkDetailsPresenter < Device::DetailsPresenter
end
15 changes: 11 additions & 4 deletions app/services/template_services/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,18 @@ def build_template(params)
# Needed for IRV structure. Should be removed eventually.
model: nil,
rack_repeat_ratio: nil,
)

# For now we have hard-coded images and padding. We should support
# users uploading their images here.
set_images_from_height(template)
tag: params[:tag],
images: params[:images]
)

if template.images.empty?
# Users can't upload images here, only use existing ones (though I
# suppose they could use fully-qualified URLs too)
set_images_from_height(template)
end

# For now we have hard-coded padding.
set_padding_from_height(template)

template
Expand Down
3 changes: 3 additions & 0 deletions app/views/api/v1/devices/details/compute_details.rabl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object @details

attributes :public_ips, :private_ips, :ssh_key, :login_user, :volume_details
4 changes: 4 additions & 0 deletions app/views/api/v1/devices/details/network_details.rabl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
object @details

attributes :admin_state_up, :dns_domain, :l2_adjacency, :mtu,
:port_security_enabled, :qos_policy, :shared
4 changes: 2 additions & 2 deletions app/views/api/v1/devices/show.rabl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ child(:template, if: @include_full_template_details) do
extends 'api/v1/templates/show'
end

glue :details do
attributes :public_ips, :private_ips, :ssh_key, :login_user, :volume_details
glue :details do |details|
extends "api/v1/devices/details/#{details.class.name.split('::').last.underscore}"
#node :type do |details|
# details.class.name
#end
Expand Down
1 change: 1 addition & 0 deletions app/views/api/v1/templates/show.rabl
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ attribute :id
attribute :name
attribute :description
attribute :height
attribute :tag

attributes :foreign_id, :vcpus, :ram, :disk
15 changes: 15 additions & 0 deletions db/migrate/20240214151411_create_device_network_details.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class CreateDeviceNetworkDetails < ActiveRecord::Migration[7.1]
def change
create_table :device_network_details, id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.boolean :admin_state_up
t.string :dns_domain
t.boolean :l2_adjacency
t.integer :mtu
t.boolean :port_security_enabled
t.boolean :shared
t.string :qos_policy

t.timestamps
end
end
end
6 changes: 6 additions & 0 deletions db/migrate/20240216123948_add_tag_to_templates.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddTagToTemplates < ActiveRecord::Migration[7.1]
def change
add_column :templates, :tag, :string, null: true
add_index :templates, :tag, unique: true
end
end
32 changes: 32 additions & 0 deletions db/migrate/20240216141238_seed_network_device_template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class SeedNetworkDeviceTemplate < ActiveRecord::Migration[7.1]
def change
reversible do |dir|

dir.up do
t = Template.new(
name: 'network',
template_type: 'Device',
tag: 'network',
version: 1,
height: 1,
depth: 2,
rows: 1,
columns: 1,
rackable: 'rackable',
simple: true,
description: 'Network',
images: {
'front' => 'switch_front_1u.png',
'rear' => 'switch_rear_1u.png',
}
)
t.save!
end

dir.down do
Template.find_by_tag('network')&.destroy!
end

end
end
end
26 changes: 26 additions & 0 deletions db/migrate/20240219161225_migrate_default_rack_template_to_tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class MigrateDefaultRackTemplateToTag < ActiveRecord::Migration[7.1]

class Template < ApplicationRecord; end

def change
reversible do |dir|
dir.up do
# Intentionally not using Template.default_rack_template here!
rack = Template.find_by(default_rack_template: true)
rack.tag = 'rack'
rack.save!
end

dir.down do
rack = Template.find_by_tag('rack')
rack.default_rack_template = true
rack.tag = nil
rack.save!
end
end

# Remove index separately so that db:rollback can recreate it
remove_index :templates, :default_rack_template, unique: true, where: "default_rack_template = true"
remove_column :templates, :default_rack_template, :boolean, default: false, null: false
end
end
18 changes: 15 additions & 3 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion docs/api/examples/create-and-populate-rack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,16 @@ echo "Moved device" >&2
"${SCRIPT_DIR}/show-device.sh" "${DEVICE_ID}"
echo

OUTPUT=$("${SCRIPT_DIR}/create-network.sh" net-1 "${RACK_ID}" f "$RACK_HEIGHT")
if [ $? -ne 0 ] ; then
# Errors will have been sent to stderr.
exit
fi
echo "Created network device"

# Leave some space at the top to allow dragging devices around the IRV.
START_U=$(( ${TEMPLATE_HEIGHT} + 1 ))
END_U=$(( $RACK_HEIGHT - 3 ))
END_U=$(( $RACK_HEIGHT - 4 ))
"${SCRIPT_DIR}/populate-rack.sh" ${RACK_ID} ${START_U} ${END_U} comp102

"${SCRIPT_DIR}/show-rack.sh" "${RACK_ID}"
Expand Down
84 changes: 84 additions & 0 deletions docs/api/examples/create-network.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/bash

set -e
set -o pipefail
# set -x

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

# The base URL against which relative URLs are constructed.
CONCERTIM_HOST=${CONCERTIM_HOST:-command.concertim.alces-flight.com}
BASE_URL="https://${CONCERTIM_HOST}/api/v1"

# Use the specified AUTH_TOKEN or generate one. If AUTH_TOKEN is being
# generated LOGIN and PASSWORD environment variables must be set.
AUTH_TOKEN=${AUTH_TOKEN:-$("${SCRIPT_DIR}"/get-auth-token.sh)}

NAME=${1}
RACK_ID=${2}
FACING=${3}
START_U=${4}

NETWORK_TEMPLATE_ID=$( "${SCRIPT_DIR}/list-templates.sh" | jq -r "sort_by(.height) | (.[] | select(.tag | . and contains(\"network\"))) | .id" )

if [ -z "${NETWORK_TEMPLATE_ID}" ]; then
echo "Couldn't find a template with tag='network'"
exit 1
fi

# The metadata below is hardcoded but it could be any valid JSON document.

BODY=$(jq --null-input \
--arg name "${NAME}" \
--arg description "This is ${NAME} network" \
--arg facing "${FACING}" \
--arg start_u "${START_U}" \
--arg rack_id "${RACK_ID}" \
--arg template_id "${NETWORK_TEMPLATE_ID}" \
'
{
"template_id": $template_id,
"device": {
"name": $name,
"description": $description,
"location": {
"facing": $facing,
"rack_id": $rack_id,
"start_u": $start_u|tonumber
},
"status": "IN_PROGRESS",
"metadata": {
"openstack_instance_id": "8f4e9068-5a39-4717-8a83-6b95e01031eb",
"status": ["build", "scheduling", ""]
},
"details": {
"type": "Device::NetworkDetails",
"admin_state_up": true,
"dns_domain": "moose.local",
"mtu": 1500
}
}
}
'
)

# Run curl with funky redirection to capture response body and status code.
BODY_FILE=$(mktemp)
HTTP_STATUS=$(
curl -s -k \
-w "%{http_code}" \
-o >(cat > "${BODY_FILE}") \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H "Authorization: Bearer ${AUTH_TOKEN}" \
-X POST "${BASE_URL}/nodes" \
-d "${BODY}"
)

if [ "${HTTP_STATUS}" == "200" ] || [ "${HTTP_STATUS}" == "201" ] ; then
cat "$BODY_FILE"
else
echo "Device creation failed" >&2
cat "$BODY_FILE" >&2
exit 1
fi
Loading

0 comments on commit 887565b

Please sign in to comment.