Skip to content

Commit

Permalink
ipmi: use efiboot option in ipmi pxe commands when required
Browse files Browse the repository at this point in the history
Fixes: #82
  • Loading branch information
Gema Gomez committed Apr 8, 2018
1 parent f7125d3 commit b0e1ae0
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Bug fixes:

- grub.netboot.tmpl: fixing position of BOOTIF= argument to solve problems with --- in cmdline being used from UI.
- ui: add missing "show all" button for machine events (#80)
- ipmi: use efiboot option in ipmi pxe commands when required (#82)

## v0.2.9 (2018-02-16)

Expand Down
28 changes: 28 additions & 0 deletions migrations/versions/138919866e75_add_efiboot_option.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""add efiboot option
Revision ID: 138919866e75
Revises: ffa897d733ca
Create Date: 2018-04-07 11:45:17.506953
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '138919866e75'
down_revision = 'ffa897d733ca'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('subarch', sa.Column('efiboot', sa.Boolean(), nullable=False, server_default='false'))
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('subarch', 'efiboot')
# ### end Alembic commands ###
25 changes: 11 additions & 14 deletions migrations/versions/5ff7c035ac37_multiarch_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"""
from alembic import op
import sqlalchemy as sa
from mr_provisioner.models import Arch, Subarch, Image
from flask import current_app

from sqlalchemy.orm import sessionmaker
Expand Down Expand Up @@ -60,28 +59,26 @@ def upgrade():
# ### end Alembic commands ###

session = Session(bind=bind)
arch = Arch(name='default')
session.add(arch)
s = sa.sql.text('INSERT INTO arch(name, description) VALUES(:name, :description) RETURNING *')
result = session.execute(s, {'name': 'default', 'description': 'Default architecture'})
arch_id = result[0]['id']
session.commit()

image = None
image_id = None
bootfile = current_app.config.get('DHCP_DEFAULT_BOOTFILE')

if bootfile and bootfile != '':
session = Session(bind=bind)
image = Image(filename=bootfile,
description='Default bootloader',
file_type='bootloader',
arch_id=arch.id,
user_id=None,
known_good=True,
public=True)
session.add(image)
s = sa.sql.text('INSERT INTO image(filename, description, file_type, arch_id, known_good, public) VALUES(:filename, :description, :file_type, :arch_id, :known_good, :public) RETURNING *')
result = session.execute(s, {'filename': bootfile, 'description': 'Default bootloader', 'arch_id': arch_id,
'file_type': 'bootloader', 'known_good': True, 'public': True})
image_id = result[0]['id']
session.commit()

session = Session(bind=bind)
subarch = Subarch(name='default', arch_id=arch.id, bootloader_id=image.id if image else None)
session.add(subarch)
s = sa.sql.text('INSERT INTO subarch(name, description) VALUES(:name, :description, :arch_id, :bootloader_id)')
session.execute(s, {'name': 'default', 'description': 'Default sub-architecture', 'arch_id': arch_id,
'bootloader_id': image_id})
session.commit()

session = Session(bind=bind)
Expand Down
8 changes: 8 additions & 0 deletions mr_provisioner/admin/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ class SubarchType(graphene.ObjectType):
name = graphene.String()
description = graphene.String()
bootloader = graphene.Field(ImageType)
efiboot = graphene.Boolean()
arch = graphene.Dynamic(lambda: graphene.Field(ArchType))


Expand Down Expand Up @@ -418,6 +419,7 @@ class Input:
name = graphene.String()
description = graphene.String()
bootloader_id = graphene.Int()
efiboot = graphene.Boolean()

ok = graphene.Boolean()
errors = graphene.List(graphene.String)
Expand Down Expand Up @@ -463,6 +465,8 @@ def mutate(root, args, context, info):

if bootloader:
subarch.bootloader_id = bootloader.id
if 'efiboot' in args:
subarch.efiboot = args.get('efiboot')

db.session.add(subarch)
try:
Expand All @@ -484,6 +488,7 @@ class Input:
name = graphene.String()
description = graphene.String()
bootloader_id = graphene.Int()
efiboot = graphene.Boolean()

ok = graphene.Boolean()
errors = graphene.List(graphene.String)
Expand Down Expand Up @@ -524,6 +529,9 @@ def mutate(root, args, context, info):
subarch.description = args.get('description')
subarch.bootloader_id = args.get('bootloader_id')

if 'efiboot' in args:
subarch.efiboot = args.get('efiboot')

try:
db.session.commit()
db.session.refresh(subarch)
Expand Down
12 changes: 12 additions & 0 deletions mr_provisioner/admin/ui/src/components/arch/arch.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Timestamp from 'grommet/components/Timestamp'
import Section from 'grommet/components/Section'
import Label from 'grommet/components/Label'
import Anchor from 'grommet/components/Anchor'
import CheckBox from 'grommet/components/CheckBox'
import { Link } from 'react-router-dom'
import { Table, TableColumn, LinkCell, TextCell, AnyCell } from '../table'
import Layer from '../layer'
Expand Down Expand Up @@ -71,6 +72,7 @@ const bootloaderName = subarch =>
const sortByName = comparators.string(['name'])
const sortByDescription = comparators.string(['description'])
const sortByBootloader = comparators.string([], bootloaderName)
const sortByEfiboot = comparators.boolean(['efiboot'])

function ArchSubarchs({ arch, onAdd, onEdit, onRemove }) {
return (
Expand Down Expand Up @@ -99,6 +101,16 @@ function ArchSubarchs({ arch, onAdd, onEdit, onRemove }) {
sortFn={sortByBootloader}
cell={<TextCell textFn={bootloaderName} />}
/>
<TableColumn
label="Efiboot"
sortFn={sortByEfiboot}
cell={
<AnyCell
fn={p =>
<CheckBox disabled={true} toggle={true} checked={p.efiboot} />}
/>
}
/>
<TableColumn
label=""
cell={
Expand Down
14 changes: 14 additions & 0 deletions mr_provisioner/admin/ui/src/components/arch/archAddSubarch.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import FormFields from 'grommet/components/FormFields'
import TextInput from 'grommet/components/TextInput'
import { TextInput2 } from '../grommetHacks'
import Button from 'grommet/components/Button'
import CheckBox from 'grommet/components/CheckBox'
import Footer from 'grommet/components/Footer'
import Select from '../select'
import { NetworkLoading, NetworkError } from '../network'
Expand Down Expand Up @@ -61,6 +62,15 @@ function ArchAddSubarch_({
</fieldset>

<fieldset>
<FormField label="EFI boot" help={null}>
<CheckBox
disabled={false}
toggle={true}
checked={fields.efiboot}
onChange={props.onChangeEfiboot}
/>
</FormField>

<FormField
label="Bootloader"
help={null}
Expand Down Expand Up @@ -107,6 +117,10 @@ const formFields = {
defaultValue: null,
accessor: e => e,
},
efiboot: {
defaultValue: false,
accessor: e => e.target.checked,
},
}

const validationRules = {
Expand Down
14 changes: 14 additions & 0 deletions mr_provisioner/admin/ui/src/components/arch/archEditSubarch.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import FormField from 'grommet/components/FormField'
import FormFields from 'grommet/components/FormFields'
import TextInput from 'grommet/components/TextInput'
import { TextInput2 } from '../grommetHacks'
import CheckBox from 'grommet/components/CheckBox'
import Button from 'grommet/components/Button'
import Footer from 'grommet/components/Footer'
import Select from '../select'
Expand Down Expand Up @@ -61,6 +62,15 @@ function ArchEditSubarch_({
</fieldset>

<fieldset>
<FormField label="EFI boot" help={null}>
<CheckBox
disabled={false}
toggle={true}
checked={fields.efiboot}
onChange={props.onChangeEfiboot}
/>
</FormField>

<FormField
label="Bootloader"
help={null}
Expand Down Expand Up @@ -114,6 +124,10 @@ const formFields = {
subarch.bootloader ? subarch.bootloader.id : null,
accessor: e => e,
},
efiboot: {
defaultValue: ({ subarch }) => subarch.efiboot,
accessor: e => e.target.checked,
},
}

const validationRules = {
Expand Down
8 changes: 8 additions & 0 deletions mr_provisioner/admin/ui/src/graphql/arch.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const archsListGQL = gql`
name
description
subarchs {
efiboot
id
name
}
Expand All @@ -24,6 +25,7 @@ export const archGQL = gql`
id
name
description
efiboot
bootloader {
id
filename
Expand Down Expand Up @@ -83,18 +85,21 @@ export const createSubarchGQL = gql`
$name: String!
$description: String
$bootloaderId: Int
$efiboot: Boolean
) {
createSubarch(
archId: $archId
name: $name
description: $description
bootloaderId: $bootloaderId
efiboot: $efiboot
) {
ok
errors
subarch {
id
name
efiboot
arch {
id
name
Expand All @@ -110,18 +115,21 @@ export const changeSubarchGQL = gql`
$name: String!
$description: String
$bootloaderId: Int
$efiboot: Boolean
) {
changeSubarch(
id: $id
name: $name
description: $description
bootloaderId: $bootloaderId
efiboot: $efiboot
) {
ok
errors
subarch {
id
name
efiboot
arch {
id
name
Expand Down
7 changes: 6 additions & 1 deletion mr_provisioner/bmc_types/moonshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@ def get_bridge_info(self, machine):

def set_bootdev(self, machine, bootdev):
bmc = machine.bmc

opts = None
if bootdev == "pxe" and machine.subarch and machine.subarch.efiboot:
opts = "efiboot"

try:
set_bootdev(bootdev, host=bmc.ip, username=bmc.username, password=bmc.password,
set_bootdev(bootdev, opts, host=bmc.ip, username=bmc.username, password=bmc.password,
bridge_info=self.get_bridge_info(machine))
except IPMIError as e:
raise BMCError("BMC error: %s" % str(e))
Expand Down
7 changes: 6 additions & 1 deletion mr_provisioner/bmc_types/plain.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ def validate_bmc_info(self, info):

def set_bootdev(self, machine, bootdev):
bmc = machine.bmc

opts = None
if bootdev == "pxe" and machine.subarch and machine.subarch.efiboot:
opts = "efiboot"

try:
set_bootdev(bootdev, host=bmc.ip, username=bmc.username, password=bmc.password)
set_bootdev(bootdev, opts, host=bmc.ip, username=bmc.username, password=bmc.password)
except IPMIError as e:
raise BMCError("BMC error: %s" % str(e))

Expand Down
9 changes: 7 additions & 2 deletions mr_provisioner/ipmi.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,16 @@ def run_command(command):
raise IPMIError("IPMI error: %s (%s)" % (str(e), e.output))


def set_bootdev(bootdev, **kwargs):
def set_bootdev(bootdev, options=None, **kwargs):
if bootdev not in ALLOWED_BOOTDEVS:
raise IPMIError("IPMI error: Uknown bootdev %s" % (bootdev))

command = build_command(["chassis", "bootdev", bootdev], **kwargs)
cmd = ["chassis", "bootdev", bootdev]
if options:
cmd += ["options=%s" % options]

command = build_command(cmd, **kwargs)

return run_command(command)


Expand Down
4 changes: 3 additions & 1 deletion mr_provisioner/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,14 @@ class Subarch(db.Model):
arch = db.relationship("Arch", foreign_keys=[arch_id], passive_deletes=True)
bootloader_id = db.Column(db.Integer, db.ForeignKey("image.id"))
bootloader = db.relationship("Image", foreign_keys=[bootloader_id], passive_deletes=True)
efiboot = db.Column(db.Boolean, nullable=False)

def __init__(self, name, arch_id, description=None, bootloader_id=None):
def __init__(self, name, arch_id, description=None, bootloader_id=None, efiboot=False):
self.name = name
self.description = description
self.arch_id = arch_id
self.bootloader_id = bootloader_id
self.efiboot = efiboot

def check_permission(self, user, min_priv_level='any'):
if user.admin:
Expand Down

0 comments on commit b0e1ae0

Please sign in to comment.