Skip to content

Add support for multiple nics with vmware cloud director in the UI #7452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 44 additions & 41 deletions modules/api/pkg/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2623,19 +2623,20 @@ func (spec *OpenNebulaNodeSpec) MarshalJSON() ([]byte, error) {
// VMwareCloudDirectorNodeSpec VMware Cloud Director node settings
// swagger:model VMwareCloudDirectorNodeSpec
type VMwareCloudDirectorNodeSpec struct {
CPUs int `json:"cpus"`
CPUCores int `json:"cpuCores"`
MemoryMB int `json:"memoryMB"`
DiskSizeGB *int64 `json:"diskSizeGB,omitempty"`
DiskIOPS *int64 `json:"diskIOPS,omitempty"`
Template string `json:"template"`
Catalog string `json:"catalog"`
StorageProfile string `json:"storageProfile"`
IPAllocationMode vmwareclouddirector.IPAllocationMode `json:"ipAllocationMode,omitempty"`
VApp string `json:"vapp,omitempty"`
Network string `json:"network,omitempty"`
PlacementPolicy *string `json:"placementPolicy,omitempty"`
SizingPolicy *string `json:"sizingPolicy,omitempty"`
CPUs int `json:"cpus"`
CPUCores int `json:"cpuCores"`
MemoryMB int `json:"memoryMB"`
DiskSizeGB *int64 `json:"diskSizeGB,omitempty"`
DiskIOPS *int64 `json:"diskIOPS,omitempty"`
Template string `json:"template"`
Catalog string `json:"catalog"`
StorageProfile string `json:"storageProfile"`
IPAllocationMode vmwareclouddirector.IPAllocationMode `json:"ipAllocationMode,omitempty"`
VApp string `json:"vapp,omitempty"`
Network string `json:"network,omitempty"`
AdditionalNetworks []string `json:"additionalNetworks,omitempty"`
PlacementPolicy *string `json:"placementPolicy,omitempty"`
SizingPolicy *string `json:"sizingPolicy,omitempty"`
// Additional metadata to set
// required: false
Metadata map[string]string `json:"metadata,omitempty"`
Expand Down Expand Up @@ -2677,35 +2678,37 @@ func (spec *VMwareCloudDirectorNodeSpec) MarshalJSON() ([]byte, error) {
}

res := struct {
CPUs int `json:"cpus"`
CPUCores int `json:"cpuCores"`
MemoryMB int `json:"memoryMB"`
DiskSizeGB *int64 `json:"diskSizeGB,omitempty"`
DiskIOPS *int64 `json:"diskIOPS,omitempty"`
Catalog string `json:"catalog"`
Template string `json:"template"`
StorageProfile string `json:"storageProfile,omitempty"`
IPAllocationMode vmwareclouddirector.IPAllocationMode `json:"ipAllocationMode,omitempty"`
VApp string `json:"vapp,omitempty"`
Network string `json:"network,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
PlacementPolicy *string `json:"placementPolicy,omitempty"`
SizingPolicy *string `json:"sizingPolicy,omitempty"`
CPUs int `json:"cpus"`
CPUCores int `json:"cpuCores"`
MemoryMB int `json:"memoryMB"`
DiskSizeGB *int64 `json:"diskSizeGB,omitempty"`
DiskIOPS *int64 `json:"diskIOPS,omitempty"`
Catalog string `json:"catalog"`
Template string `json:"template"`
StorageProfile string `json:"storageProfile,omitempty"`
IPAllocationMode vmwareclouddirector.IPAllocationMode `json:"ipAllocationMode,omitempty"`
VApp string `json:"vapp,omitempty"`
Network string `json:"network,omitempty"`
AdditionalNetworks []string `json:"additionalNetworks,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
PlacementPolicy *string `json:"placementPolicy,omitempty"`
SizingPolicy *string `json:"sizingPolicy,omitempty"`
}{
CPUs: spec.CPUs,
CPUCores: spec.CPUCores,
MemoryMB: spec.MemoryMB,
DiskSizeGB: spec.DiskSizeGB,
DiskIOPS: spec.DiskIOPS,
Catalog: spec.Catalog,
Template: spec.Template,
StorageProfile: spec.StorageProfile,
IPAllocationMode: spec.IPAllocationMode,
VApp: spec.VApp,
Network: spec.Network,
Metadata: spec.Metadata,
PlacementPolicy: spec.PlacementPolicy,
SizingPolicy: spec.SizingPolicy,
CPUs: spec.CPUs,
CPUCores: spec.CPUCores,
MemoryMB: spec.MemoryMB,
DiskSizeGB: spec.DiskSizeGB,
DiskIOPS: spec.DiskIOPS,
Catalog: spec.Catalog,
Template: spec.Template,
StorageProfile: spec.StorageProfile,
IPAllocationMode: spec.IPAllocationMode,
VApp: spec.VApp,
Network: spec.Network,
AdditionalNetworks: spec.AdditionalNetworks,
Metadata: spec.Metadata,
PlacementPolicy: spec.PlacementPolicy,
SizingPolicy: spec.SizingPolicy,
}

return json.Marshal(&res)
Expand Down
35 changes: 25 additions & 10 deletions modules/api/pkg/machine/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,32 @@ func GetAPIV2NodeCloudSpec(machineSpec clusterv1alpha1.MachineSpec) (*apiv1.Node
if err := json.Unmarshal(decodedProviderSpec.CloudProviderSpec.Raw, &config); err != nil {
return nil, fmt.Errorf("failed to parse VMWare Cloud Director config: %w", err)
}

var networks []string

for _, network := range config.Networks {
networks = append(networks, network.Value)
}

network := config.Network.Value

if len(networks) > 0 {
network = networks[0]
networks = networks[1:]
}

cloudSpec.VMwareCloudDirector = &apiv1.VMwareCloudDirectorNodeSpec{
CPUs: int(config.CPUs),
CPUCores: int(config.CPUCores),
MemoryMB: int(config.MemoryMB),
DiskSizeGB: config.DiskSizeGB,
Template: config.Template.Value,
Catalog: config.Catalog.Value,
DiskIOPS: config.DiskIOPS,
VApp: config.VApp.Value,
Network: config.Network.Value,
IPAllocationMode: config.IPAllocationMode,
CPUs: int(config.CPUs),
CPUCores: int(config.CPUCores),
MemoryMB: int(config.MemoryMB),
DiskSizeGB: config.DiskSizeGB,
Template: config.Template.Value,
Catalog: config.Catalog.Value,
DiskIOPS: config.DiskIOPS,
VApp: config.VApp.Value,
Network: network,
AdditionalNetworks: networks,
IPAllocationMode: config.IPAllocationMode,
}

if config.StorageProfile != nil {
Expand Down
21 changes: 18 additions & 3 deletions modules/api/pkg/resources/machine/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,30 @@ func GetVMwareCloudDirectorProviderConfig(c *kubermaticv1.Cluster, nodeSpec apiv
config.PlacementPolicy = nodeSpec.Cloud.VMwareCloudDirector.PlacementPolicy
}

var networks []providerconfig.ConfigVarString

switch {
case nodeSpec.Cloud.VMwareCloudDirector.Network != "":
config.Network = providerconfig.ConfigVarString{Value: nodeSpec.Cloud.VMwareCloudDirector.Network}
networks = append(networks, providerconfig.ConfigVarString{Value: nodeSpec.Cloud.VMwareCloudDirector.Network})
case c.Spec.Cloud.VMwareCloudDirector.OVDCNetwork != "":
config.Network = providerconfig.ConfigVarString{Value: c.Spec.Cloud.VMwareCloudDirector.OVDCNetwork}
networks = append(networks, providerconfig.ConfigVarString{Value: c.Spec.Cloud.VMwareCloudDirector.OVDCNetwork})
case len(c.Spec.Cloud.VMwareCloudDirector.OVDCNetworks) > 0:
config.Network = providerconfig.ConfigVarString{Value: c.Spec.Cloud.VMwareCloudDirector.OVDCNetworks[0]}
networks = append(networks, providerconfig.ConfigVarString{Value: c.Spec.Cloud.VMwareCloudDirector.OVDCNetworks[0]})
}

networkLoop:
for _, network := range nodeSpec.Cloud.VMwareCloudDirector.AdditionalNetworks {
// Check if network is already registered in the slice
for _, registered := range networks {
if registered.Value == network {
continue networkLoop
}
}
networks = append(networks, providerconfig.ConfigVarString{Value: network})
}

config.Networks = networks

return config, nil
}

Expand Down
28 changes: 28 additions & 0 deletions modules/web/proxy-sva.conf.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2021 The Kubermatic Kubernetes Platform contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const PROXY_CONFIG = [
{
context: ['/api/**'],
target: 'https://k8s.sva-cloud.dev',
changeOrigin: true,
headers: {
Origin: 'https://k8s.sva-cloud.dev',
},
secure: false,
ws: true,
},
];

module.exports = PROXY_CONFIG;
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ enum Controls {
SizingPolicy = 'sizingPolicy',
Template = 'template',
Network = 'network',
AdditionalNetworks = 'additionalNetworks',
}

enum StorageProfileState {
Expand Down Expand Up @@ -201,7 +202,8 @@ export class VMwareCloudDirectorBasicNodeDataComponent
this.form.get(Controls.DiskSizeGB).valueChanges,
this.form.get(Controls.DiskIOPs).valueChanges,
this.form.get(Controls.IPAllocationMode).valueChanges,
this.form.get(Controls.Network).valueChanges
this.form.get(Controls.Network).valueChanges,
this.form.get(Controls.AdditionalNetworks).valueChanges
)
.pipe(takeUntil(this._unsubscribe))
.subscribe(_ => (this._nodeDataService.nodeData = this._getNodeData()));
Expand All @@ -217,7 +219,8 @@ export class VMwareCloudDirectorBasicNodeDataComponent
this.form.get(Controls.Catalog).valueChanges,
this.form.get(Controls.PlacementPolicy).valueChanges,
this.form.get(Controls.SizingPolicy).valueChanges,
this.form.get(Controls.Network).valueChanges
this.form.get(Controls.Network).valueChanges,
this.form.get(Controls.AdditionalNetworks).valueChanges
)
.pipe(filter(_ => this.isEnterpriseEdition))
.pipe(takeUntil(this._unsubscribe))
Expand Down Expand Up @@ -339,10 +342,21 @@ export class VMwareCloudDirectorBasicNodeDataComponent
}

onNetworkChanged(network: string): void {
const additionalNetworksControl = this.form.get(Controls.AdditionalNetworks);

if (additionalNetworksControl.value && additionalNetworksControl.value.includes(network)) {
additionalNetworksControl.setValue(additionalNetworksControl.value.filter(n => n !== network));
}

this._nodeDataService.nodeData.spec.cloud.vmwareclouddirector.network = network;
this._nodeDataService.nodeDataChanges.next(this._nodeDataService.nodeData);
}

onAdditionalNetworkChanged(networks: string[]): void {
this._nodeDataService.nodeData.spec.cloud.vmwareclouddirector.additionalNetworks = networks;
this._nodeDataService.nodeDataChanges.next(this._nodeDataService.nodeData);
}

onTemplateChanged(template: string): void {
this.selectedTemplate = template;
this._nodeDataService.nodeData.spec.cloud.vmwareclouddirector.template = template;
Expand All @@ -351,6 +365,10 @@ export class VMwareCloudDirectorBasicNodeDataComponent

updateSelectedNetwork(): void {
const networkControl = this.form.get(Controls.Network);
const additionalNetworksControl = this.form.get(Controls.AdditionalNetworks);

additionalNetworksControl.setValue(additionalNetworksControl.value.filter(n => this.networks.includes(n)));

if (networkControl.value && this.networks.includes(networkControl.value)) {
return;
}
Expand Down Expand Up @@ -381,9 +399,8 @@ export class VMwareCloudDirectorBasicNodeDataComponent
[Controls.Catalog]: this._builder.control(values ? values.catalog : defaults.catalog, [Validators.required]),
[Controls.PlacementPolicy]: this._builder.control(values ? values.placementPolicy : defaults.placementPolicy),
[Controls.SizingPolicy]: this._builder.control(values ? values.sizingPolicy : defaults.sizingPolicy),
[Controls.Network]: this._builder.control(values && values.network ? values.network : this.networks[0], [
Validators.required,
]),
[Controls.Network]: this._builder.control(values?.network ?? this.networks[0], Validators.required),
[Controls.AdditionalNetworks]: this._builder.control(values?.additionalNetworks ?? []),
});
}

Expand Down Expand Up @@ -573,6 +590,7 @@ export class VMwareCloudDirectorBasicNodeDataComponent
diskIOPS: this.form.get(Controls.DiskIOPs).value,
ipAllocationMode: this.form.get(Controls.IPAllocationMode).value,
network: this.form.get(Controls.Network).value,
additionalNetworks: this.form.get(Controls.AdditionalNetworks).value,
} as VMwareCloudDirectorNodeSpec,
} as NodeCloudSpec,
} as NodeSpec,
Expand All @@ -595,6 +613,7 @@ export class VMwareCloudDirectorBasicNodeDataComponent
[Controls.PlacementPolicy]: this.form.get(Controls.PlacementPolicy).value?.[ComboboxControls.Select],
[Controls.SizingPolicy]: this.form.get(Controls.SizingPolicy).value?.[ComboboxControls.Select],
[Controls.Network]: this.form.get(Controls.Network).value,
[Controls.AdditionalNetworks]: this.form.get(Controls.AdditionalNetworks).value,
} as VMwareCloudDirectorNodeSpec,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@
</mat-select>
</mat-form-field>


<mat-form-field fxFlex *ngIf="networks.length > 1">
<mat-label>Addtional Networks</mat-label>
<mat-select [formControlName]="Controls.AdditionalNetworks"
(selectionChange)="onAdditionalNetworkChanged($event.value)"
disableOptionCentering
multiple
kmValueChangedIndicator>
<mat-option *ngFor="let network of networks"
[value]="network"
[disabled]="network == form.get(Controls.Network).value"> {{network}} </mat-option>
</mat-select>
</mat-form-field>

<km-combobox #placementPolicyCombobox
[selected]="selectedPlacementPolicy"
[options]="placementPolicies"
Expand Down
1 change: 1 addition & 0 deletions modules/web/src/app/shared/entity/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ export class VMwareCloudDirectorNodeSpec {
vapp?: string;
catalog: string;
network?: string;
additionalNetworks: string[];
template: string;
placementPolicy?: string;
sizingPolicy?: string;
Expand Down