Skip to content

Commit

Permalink
[#1230] Specify relay addresses for subnet
Browse files Browse the repository at this point in the history
  • Loading branch information
msiodelski committed Nov 29, 2023
1 parent 8d4008e commit 9fddda9
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 49 deletions.
2 changes: 2 additions & 0 deletions webui/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ import { SharedParametersFormComponent } from './shared-parameters-form/shared-p
import { SubnetFormComponent } from './subnet-form/subnet-form.component'
import { AddressPoolFormComponent } from './address-pool-form/address-pool-form.component'
import { PrefixPoolFormComponent } from './prefix-pool-form/prefix-pool-form.component'
import { ArrayValueSetFormComponent } from './array-value-set-form/array-value-set-form.component'

/** Create the OpenAPI client configuration. */
export function cfgFactory() {
Expand Down Expand Up @@ -203,6 +204,7 @@ export function cfgFactory() {
SubnetFormComponent,
AddressPoolFormComponent,
PrefixPoolFormComponent,
ArrayValueSetFormComponent,
],
imports: [
BrowserModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p-chips ngDefaultControl [allowDuplicate]="false" [addOnBlur]="true" [formControl]="classFormControl"> </p-chips>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
:host ::ng-deep .p-chips
width: 500px

.p-chips-multiple-container
width: 100%

.p-chips-token
background: var(--primary-100)
color: var(--text-color)
margin-top: 2px
margin-bottom: 2px

.p-chips-input-token input
margin-top: 2px
margin-bottom: 2px
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'

import { ArrayValueSetFormComponent } from './array-value-set-form.component'
import { Chips, ChipsModule } from 'primeng/chips'
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NoopAnimationsModule } from '@angular/platform-browser/animations'
import { By } from '@angular/platform-browser'

describe('ArrayValueSetFormComponent', () => {
let component: ArrayValueSetFormComponent<string>
let fixture: ComponentFixture<ArrayValueSetFormComponent<string>>

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ArrayValueSetFormComponent],
imports: [ChipsModule, FormsModule, NoopAnimationsModule, ReactiveFormsModule],
})
fixture = TestBed.createComponent(ArrayValueSetFormComponent<string>)
component = fixture.componentInstance
component.classFormControl = new FormControl<string>(null)
fixture.detectChanges()
})

it('should create', () => {
expect(component).toBeTruthy()
})

it('should display chips component', () => {
const chips = fixture.debugElement.query(By.directive(Chips))
const chipsComponent = chips.componentInstance as Chips
expect(chipsComponent).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Component, Input } from '@angular/core'
import { FormControl } from '@angular/forms'

/**
* A component providing a form control for specifying an array of values.
*
* @tparam T Type of the values to specify.
*/
@Component({
selector: 'app-array-value-set-form',
templateUrl: './array-value-set-form.component.html',
styleUrls: ['./array-value-set-form.component.sass'],
})
export class ArrayValueSetFormComponent<T> {
/**
* A form bound to the "chips" input box holding the list of selected
* class names.
*/
@Input() classFormControl: FormControl<T>
}
1 change: 1 addition & 0 deletions webui/src/app/forms/shared-parameter-form-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface SharedParameterForm {
interface EditableParameterSpec<T> {
type: string
values?: T[]
isArray?: boolean
min?: number
max?: number
fractionDigits?: number
Expand Down
28 changes: 20 additions & 8 deletions webui/src/app/forms/subnet-set-form.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { TestBed } from '@angular/core/testing'

import {
AddressPoolForm,
KeaPoolParametersForm,
KeaSubnetParametersForm,
SubnetSetFormService,
} from './subnet-set-form.service'
import { KeaPoolParametersForm, KeaSubnetParametersForm, SubnetSetFormService } from './subnet-set-form.service'
import { KeaConfigPoolParameters, KeaConfigSubnetDerivedParameters, Pool, Subnet } from '../backend'
import { SharedParameterFormGroup } from './shared-parameter-form-group'
import { FormControl, FormGroup, UntypedFormArray, UntypedFormControl } from '@angular/forms'
Expand Down Expand Up @@ -865,6 +860,9 @@ describe('SubnetSetFormService', () => {
rapidCommit: true,
serverHostname: 'foo.example.org.',
storeExtendedInfo: true,
relay: {
ipAddresses: ['192.0.2.1', '192.0.2.2', '192.0.2.3'],
},
},
{
cacheThreshold: 0.5,
Expand Down Expand Up @@ -909,6 +907,9 @@ describe('SubnetSetFormService', () => {
rapidCommit: false,
serverHostname: 'bar.example.org.',
storeExtendedInfo: false,
relay: {
ipAddresses: ['192.0.2.1', '192.0.2.2', '192.0.2.3'],
},
},
]
let form = service.convertKeaSubnetParametersToForm(IPType.IPv4, parameters)
Expand Down Expand Up @@ -1557,7 +1558,7 @@ describe('SubnetSetFormService', () => {

it('should create a default form for an IPv4 subnet', () => {
let form = service.createDefaultKeaSubnetParametersForm(IPType.IPv4)
expect(Object.keys(form.controls).length).toBe(37)
expect(Object.keys(form.controls).length).toBe(38)

for (const key of Object.keys(form.controls)) {
let control = form.get(key) as SharedParameterFormGroup<any>
Expand All @@ -1569,7 +1570,7 @@ describe('SubnetSetFormService', () => {

it('should create a default form for an IPv6 subnet', () => {
let form = service.createDefaultKeaSubnetParametersForm(IPType.IPv6)
expect(Object.keys(form.controls).length).toBe(35)
expect(Object.keys(form.controls).length).toBe(36)

for (const key of Object.keys(form.controls)) {
let control = form.get(key) as SharedParameterFormGroup<any>
Expand Down Expand Up @@ -1882,18 +1883,29 @@ describe('SubnetSetFormService', () => {
},
[new FormControl<boolean>(true), new FormControl<boolean>(false), new FormControl<boolean>(false)]
),
relayAddresses: new SharedParameterFormGroup<string[]>(
{
type: 'string',
},
[new FormControl<string[]>(['192.0.2.1', '192.0.2.2']), new FormControl<string[]>(['192.0.2.2'])]
),
})
)
expect(params.length).toBe(3)
expect(params[0].cacheThreshold).toBe(0.5)
expect(params[0].allocator).toBe('flq')
expect(params[0].authoritative).toBeTrue()
expect(params[0].relay).toBeTruthy()
expect(params[0].relay.ipAddresses).toEqual(['192.0.2.1', '192.0.2.2'])
expect(params[1].cacheThreshold).toBe(0.5)
expect(params[1].allocator).toBe('random')
expect(params[1].authoritative).toBeFalse()
expect(params[1].relay).toBeTruthy()
expect(params[1].relay.ipAddresses).toEqual(['192.0.2.2'])
expect(params[2].cacheThreshold).toBeFalsy()
expect(params[2].allocator).toBeFalsy()
expect(params[2].authoritative).toBeFalse()
expect(params[2].relay).toBeFalsy()
})

it('should convert a form to subnet', () => {
Expand Down
32 changes: 31 additions & 1 deletion webui/src/app/forms/subnet-set-form.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface KeaSubnetParametersForm {
rapidCommit?: SharedParameterFormGroup<boolean>
serverHostname?: SharedParameterFormGroup<string>
storeExtendedInfo?: SharedParameterFormGroup<boolean>
relayAddresses?: SharedParameterFormGroup<string[]>
}

/**
Expand Down Expand Up @@ -592,6 +593,23 @@ export class SubnetSetFormService {
},
parameters.map((params) => new FormControl<boolean>(params.storeExtendedInfo))
),
relayAddresses: new SharedParameterFormGroup<string[]>(
{
type: 'string',
isArray: true,
invalidText:
ipType === IPType.IPv4
? 'Please specify valid IPv4 addresses.'
: 'Please specify valid IPv6 addresses.',
},
parameters.map(
(params) =>
new FormControl<string[]>(
params.relay?.ipAddresses,
ipType === IPType.IPv4 ? StorkValidators.ipv4() : StorkValidators.ipv6()
)
)
),
}
// DHCPv4 parameters.
switch (ipType) {
Expand Down Expand Up @@ -690,7 +708,19 @@ export class SubnetSetFormService {
* @returns An array of parameter sets for different servers.
*/
convertFormToKeaSubnetParameters(form: FormGroup<KeaSubnetParametersForm>): KeaConfigSubnetDerivedParameters[] {
return this.convertFormToKeaParameters(form)
const convertedParameters = this.convertFormToKeaParameters<
KeaSubnetParametersForm,
KeaConfigSubnetDerivedParameters
>(form)
for (let parameters of convertedParameters) {
if ('relayAddresses' in parameters) {
parameters.relay = {
ipAddresses: parameters.relayAddresses as string[],
}
delete parameters['relayAddresses']
}
}
return convertedParameters
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@
>
</p-dropdown>
<ng-template #noValuesCase>
<input pInputText [formControlName]="index" class="full-width" />
<app-array-value-set-form
*ngIf="controls.data?.isArray; else noArrayCase"
[classFormControl]="control"
>
</app-array-value-set-form>
<ng-template #noArrayCase>
<input pInputText [formControlName]="index" class="full-width" />
</ng-template>
</ng-template>
</ng-container>
<ng-container *ngSwitchCase="'boolean'">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ComponentFixture, TestBed, tick } from '@angular/core/testing'
import { ComponentFixture, TestBed } from '@angular/core/testing'

import { SharedParametersFormComponent } from './shared-parameters-form.component'
import { SharedParameterFormGroup } from '../forms/shared-parameter-form-group'
Expand All @@ -23,6 +23,7 @@ import { TriStateCheckboxModule } from 'primeng/tristatecheckbox'
import { OverlayPanelModule } from 'primeng/overlaypanel'
import { StorkValidators } from '../validators'
import { By } from '@angular/platform-browser'
import { ArrayValueSetFormComponent } from '../array-value-set-form/array-value-set-form.component'

/**
* Intrface to the form used in the unit tests.
Expand All @@ -34,6 +35,7 @@ interface SubnetForm {
ddnsGeneratedPrefix?: SharedParameterFormGroup<string>
ddnsOverrideClientUpdate?: SharedParameterFormGroup<boolean>
requireClientClasses?: SharedParameterFormGroup<string[]>
relayAddresses?: SharedParameterFormGroup<string[]>
}

describe('SharedParametersFormComponent', () => {
Expand All @@ -42,7 +44,7 @@ describe('SharedParametersFormComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [DhcpClientClassSetFormComponent, SharedParametersFormComponent],
declarations: [ArrayValueSetFormComponent, DhcpClientClassSetFormComponent, SharedParametersFormComponent],
imports: [
ButtonModule,
CheckboxModule,
Expand Down Expand Up @@ -113,6 +115,16 @@ describe('SharedParametersFormComponent', () => {
},
[new FormControl(['foo', 'bar']), new FormControl(['foo', 'bar', 'auf'])]
),
relayAddresses: new SharedParameterFormGroup(
{
type: 'string',
isArray: true,
},
[
new FormControl(['192.0.2.1', '192.0.2.2'], StorkValidators.ipv4),
new FormControl(['192.0.2.1', '192.0.2.2', '192.0.2.3']),
]
),
})
fixture.detectChanges()

Expand All @@ -123,11 +135,12 @@ describe('SharedParametersFormComponent', () => {
'cacheThreshold',
'ddnsGeneratedPrefix',
'ddnsOverrideClientUpdate',
'relayAddresses',
'requireClientClasses',
])

let allRows = fixture.debugElement.queryAll(By.css('tr'))
expect(allRows.length).toBe(7)
expect(allRows.length).toBe(8)

// Validate the table header.
let cells = allRows[0].queryAll(By.css('th'))
Expand Down Expand Up @@ -218,9 +231,26 @@ describe('SharedParametersFormComponent', () => {
checkbox = cells[2].query(By.css('p-checkbox'))
expect(checkbox).toBeTruthy()

// Require Client Classes.
// Relay
cells = allRows[6].queryAll(By.css('td'))
expect(cells.length).toBe(3)
expect(cells[0].nativeElement.innerText).toBe('Relay Addresses')
controls = cells[1].queryAll(By.css('app-array-value-set-form'))
expect(controls.length).toBe(2)
tags = cells[1].queryAll(By.css('p-tag'))
expect(tags.length).toBe(2)
expect(tags[0].nativeElement.innerText).toBe('server 1')
expect(tags[1].nativeElement.innerText).toBe('server 2')
btns = cells[1].queryAll(By.css('[label=Clear]'))
expect(btns.length).toBe(2)
expect(btns[0].nativeElement.innerText).toBe('Clear')
expect(btns[1].nativeElement.innerText).toBe('Clear')
checkbox = cells[2].query(By.css('p-checkbox'))
expect(checkbox).toBeTruthy()

// Require Client Classes.
cells = allRows[7].queryAll(By.css('td'))
expect(cells.length).toBe(3)
expect(cells[0].nativeElement.innerText).toBe('Require Client Classes')
controls = cells[1].queryAll(By.css('app-dhcp-client-class-set-form'))
expect(controls.length).toBe(2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { moduleMetadata, Meta, Story, applicationConfig } from '@storybook/angul
import { SharedParametersFormComponent } from './shared-parameters-form.component'
import { NoopAnimationsModule } from '@angular/platform-browser/animations'
import { TableModule } from 'primeng/table'
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'
import { InputNumberModule } from 'primeng/inputnumber'
import { DhcpClientClassSetFormComponent } from '../dhcp-client-class-set-form/dhcp-client-class-set-form.component'
import { ChipsModule } from 'primeng/chips'
Expand All @@ -14,6 +14,7 @@ import { SharedParameterFormGroup } from '../forms/shared-parameter-form-group'
import { TriStateCheckboxModule } from 'primeng/tristatecheckbox'
import { CheckboxModule } from 'primeng/checkbox'
import { StorkValidators } from '../validators'
import { ArrayValueSetFormComponent } from '../array-value-set-form/array-value-set-form.component'

interface SubnetForm {
allocator: SharedParameterFormGroup<string>
Expand All @@ -22,6 +23,7 @@ interface SubnetForm {
ddnsGeneratedPrefix: SharedParameterFormGroup<string>
ddnsOverrideClientUpdate: SharedParameterFormGroup<boolean>
requireClientClasses: SharedParameterFormGroup<string[]>
relayAddresses: SharedParameterFormGroup<string[]>
}

export default {
Expand Down Expand Up @@ -53,7 +55,7 @@ export default {
OverlayPanelModule,
ReactiveFormsModule,
],
declarations: [SharedParametersFormComponent, DhcpClientClassSetFormComponent],
declarations: [ArrayValueSetFormComponent, DhcpClientClassSetFormComponent, SharedParametersFormComponent],
}),
],
} as Meta
Expand Down Expand Up @@ -104,6 +106,16 @@ VariousParameters.args = {
},
[new FormControl<boolean>(true), new FormControl<boolean>(true)]
),
relayAddresses: new SharedParameterFormGroup(
{
type: 'string',
isArray: true,
},
[
new FormControl<string[]>(['192.0.2.1', '192.0.2.2', '192.0.2.3'], StorkValidators.ipv4()),
new FormControl<string[]>(['192.0.2.1', '192.0.2.2'], StorkValidators.ipv4()),
]
),
requireClientClasses: new SharedParameterFormGroup(
{
type: 'client-classes',
Expand Down
Loading

0 comments on commit 9fddda9

Please sign in to comment.