Skip to content

Commit

Permalink
Gateway API class selector in K8s Gateway Istio config wizard (#6585)
Browse files Browse the repository at this point in the history
* Gateway API class selector in K8s Gateway Istio config wizard

* Added K8s Gateway Class selector in Service wizard.
  • Loading branch information
hhovsepy committed Sep 12, 2023
1 parent 178551a commit 405c6ef
Show file tree
Hide file tree
Showing 15 changed files with 91 additions and 9 deletions.
4 changes: 4 additions & 0 deletions business/istio_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,10 @@ func (in *IstioConfigService) IsGatewayAPI(cluster string) bool {
return in.userClients[cluster].IsGatewayAPI()
}

func (in *IstioConfigService) GatewayAPIClasses() []config.GatewayAPIClass {
return kubernetes.GatewayAPIClasses()
}

// Check if istio Ambient profile was enabled
// ATM it is defined in the istio-cni-config configmap
func (in *IstioConfigService) IsAmbientEnabled() bool {
Expand Down
4 changes: 2 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,8 @@ type ComponentStatus struct {
}

type GatewayAPIClass struct {
Name string `yaml:"name,omitempty"`
ClassName string `yaml:"class_name,omitempty"`
Name string `yaml:"name,omitempty" json:"name,omitempty"`
ClassName string `yaml:"class_name,omitempty" json:"className,omitempty"`
}

// ExternalServices holds configurations for other systems that Kiali depends on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const propsToShow = [
'authStrategy',
'clusters',
'gatewayAPIEnabled',
'gatewayAPIClasses',
'istioConfigMap',
'istioIdentityDomain',
'istioNamespace',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/IstioWizards/GatewaySelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type GatewaySelectorState = {
gwHostsValid: boolean;
newGateway: boolean;
selectedGateway: string;
gatewayClass: string;
addMesh: boolean;
port: number;
};
Expand All @@ -53,6 +54,7 @@ export class GatewaySelector extends React.Component<Props, GatewaySelectorState
gwHostsValid: true,
newGateway: props.gateways.length === 0,
selectedGateway: props.gateways.length > 0 ? (props.gateway !== '' ? props.gateway : props.gateways[0]) : '',
gatewayClass: '',
addMesh: props.isMesh,
port: 80
};
Expand Down
26 changes: 26 additions & 0 deletions frontend/src/components/IstioWizards/K8sGatewaySelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { GATEWAY_TOOLTIP, wizardTooltip } from './WizardHelp';
import { isValid } from 'utils/Common';
import { isK8sGatewayHostValid } from '../../utils/IstioConfigUtils';
import { serverConfig } from '../../config';

type Props = {
serviceName: string;
Expand All @@ -30,6 +31,7 @@ export type K8sGatewaySelectorState = {
gwHostsValid: boolean;
newGateway: boolean;
selectedGateway: string;
gatewayClass: string;
// @TODO add Mesh is not supported yet
addMesh: boolean;
port: number;
Expand All @@ -53,6 +55,7 @@ export class K8sGatewaySelector extends React.Component<Props, K8sGatewaySelecto
newGateway: props.k8sGateways.length === 0,
selectedGateway:
props.k8sGateways.length > 0 ? (props.gateway !== '' ? props.gateway : props.k8sGateways[0]) : '',
gatewayClass: serverConfig.gatewayAPIClasses[0].className,
addMesh: false,
port: 80
};
Expand Down Expand Up @@ -120,6 +123,15 @@ export class K8sGatewaySelector extends React.Component<Props, K8sGatewaySelecto
return this.state.gwHostsValid;
};

onChangeGatewayClass = (_event, value) => {
this.setState(
{
gatewayClass: value
},
() => this.props.onGatewayChange(this.isGatewayValid(), this.state)
);
};

render() {
return (
<Form isHorizontal={true}>
Expand Down Expand Up @@ -174,6 +186,20 @@ export class K8sGatewaySelector extends React.Component<Props, K8sGatewaySelecto
)}
{this.state.newGateway && (
<>
{serverConfig.gatewayAPIClasses.length > 1 && (
<FormGroup label="Gateway Class" fieldId="gatewayClass">
<FormSelect
value={this.state.gatewayClass}
onChange={this.onChangeGatewayClass}
id="gatewayClass"
name="gatewayClass"
>
{serverConfig.gatewayAPIClasses.map((option, index) => (
<FormSelectOption key={index} value={option.className} label={option.name} />
))}
</FormSelect>
</FormGroup>
)}
<FormGroup fieldId="gwPort" label="Port">
<TextInput
id="gwPort"
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/IstioWizards/ServiceWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
gwHostsValid: false,
newGateway: false,
selectedGateway: '',
gatewayClass: '',
addMesh: false,
port: 80
};
Expand All @@ -257,6 +258,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
gwHostsValid: false,
newGateway: false,
selectedGateway: '',
gatewayClass: '',
addMesh: false,
port: 80
};
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/IstioWizards/WizardActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ export const buildIstioConfig = (wProps: ServiceWizardProps, wState: ServiceWiza
}
},
spec: {
gatewayClassName: 'istio',
gatewayClassName: wState.k8sGateway.gatewayClass,
listeners: [
{
name: 'default',
Expand Down Expand Up @@ -1842,7 +1842,7 @@ export const buildK8sGateway = (name: string, namespace: string, state: K8sGatew
},
spec: {
// Default for istio scenarios, user may change it editing YAML
gatewayClassName: 'istio',
gatewayClassName: state.gatewayClass,
listeners: state.listeners.map(s => ({
name: s.name,
port: s.port,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/config/ServerConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const defaultServerConfig: ComputedServerConfig = {
clusters: {},
durations: {},
gatewayAPIEnabled: false,
gatewayAPIClasses: [],
logLevel: '',
healthConfig: {
rate: []
Expand Down
28 changes: 27 additions & 1 deletion frontend/src/pages/IstioConfigNew/K8sGatewayForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as React from 'react';
// Use TextInputBase like workaround while PF4 team work in https://github.com/patternfly/patternfly-react/issues/4072
import { FormGroup } from '@patternfly/react-core';
import { FormGroup, FormSelect, FormSelectOption } from '@patternfly/react-core';
import { AddressList } from './GatewayForm/AddressList';
import { Address, Listener, MAX_PORT, MIN_PORT } from '../../types/IstioObjects';
import { ListenerList } from './GatewayForm/ListenerList';
import { isValidHostname, isValidName } from './GatewayForm/ListenerBuilder';
import { isValidAddress } from './GatewayForm/AddressBuilder';
import { serverConfig } from '../../config';

export const K8SGATEWAY = 'K8sGateway';
export const K8SGATEWAYS = 'k8sgateways';
Expand All @@ -17,13 +18,15 @@ type Props = {

// Gateway and Sidecar states are consolidated in the parent page
export type K8sGatewayState = {
gatewayClass: string;
listeners: Listener[];
addresses: Address[];
validHosts: boolean;
listenersForm: ListenerForm[];
};

export const initK8sGateway = (): K8sGatewayState => ({
gatewayClass: serverConfig.gatewayAPIClasses[0].className,
listeners: [],
addresses: [],
validHosts: false,
Expand Down Expand Up @@ -83,9 +86,32 @@ export class K8sGatewayForm extends React.Component<Props, K8sGatewayState> {
this.setState({ addresses: addresses }, () => this.props.onChange(this.state));
};

onChangeGatewayClass = (_event, value) => {
this.setState(
{
gatewayClass: value
},
() => this.props.onChange(this.state)
);
};

render() {
return (
<>
{serverConfig.gatewayAPIClasses.length > 1 && (
<FormGroup label="Gateway Class" fieldId="gatewayClass">
<FormSelect
value={this.state.gatewayClass}
onChange={this.onChangeGatewayClass}
id="gatewayClass"
name="gatewayClass"
>
{serverConfig.gatewayAPIClasses.map((option, index) => (
<FormSelectOption key={index} value={option.className} label={option.name} />
))}
</FormSelect>
</FormGroup>
)}
<FormGroup label="Listeners" fieldId="listener" isRequired={true}>
<ListenerList
onChange={this.onChangeListener}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export const serverRateConfig = {
ambientEnabled: false,
clusters: {},
gatewayAPIEnabled: false,
gatewayAPIClasses: [],
logLevel: '',
kialiFeatureFlags: {
certificatesInformationIndicators: {
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/types/ServerConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ interface KialiFeatureFlags {
uiDefaults: UIDefaults;
}

export interface GatewayAPIClass {
name: string;
className: string;
}

// Not based exactly on Kiali configuration but rather whether things like prometheus config
// allow for certain Kiali features. True means the feature is crippled, false means supported.
export interface KialiCrippledFeatures {
Expand Down Expand Up @@ -121,6 +126,7 @@ export interface ServerConfig {
clusters: { [key: string]: MeshCluster };
deployment: DeploymentConfig;
gatewayAPIEnabled: boolean;
gatewayAPIClasses: GatewayAPIClass[];
healthConfig: HealthConfig;
installationTag?: string;
istioAnnotations: IstioAnnotations;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/__testData__/HealthConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const healthConfig = {
ambientEnabled: false,
clusters: {},
gatewayAPIEnabled: false,
gatewayAPIClasses: [],
logLevel: '',
kialiFeatureFlags: {
certificatesInformationIndicators: {
Expand Down
2 changes: 2 additions & 0 deletions handlers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type PublicConfig struct {
Clusters map[string]kubernetes.Cluster `json:"clusters,omitempty"`
Deployment DeploymentConfig `json:"deployment,omitempty"`
GatewayAPIEnabled bool `json:"gatewayAPIEnabled,omitempty"`
GatewayAPIClasses []config.GatewayAPIClass `json:"gatewayAPIClasses,omitempty"`
HealthConfig config.HealthConfig `json:"healthConfig,omitempty"`
InstallationTag string `json:"installationTag,omitempty"`
IstioAnnotations IstioAnnotations `json:"istioAnnotations,omitempty"`
Expand Down Expand Up @@ -111,6 +112,7 @@ func Config(w http.ResponseWriter, r *http.Request) {
// @TODO hardcoded home cluster
publicConfig.GatewayAPIEnabled = layer.IstioConfig.IsGatewayAPI(config.KubernetesConfig.ClusterName)
publicConfig.AmbientEnabled = layer.IstioConfig.IsAmbientEnabled()
publicConfig.GatewayAPIClasses = layer.IstioConfig.GatewayAPIClasses()

// Fetch the list of all clusters in the mesh
// One usage of this data is to cross-link Kiali instances, when possible.
Expand Down
5 changes: 1 addition & 4 deletions kubernetes/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,9 @@ func FilterSupportedGateways(gateways []*networking_v1beta1.Gateway) []*networki

func FilterSupportedK8sGateways(gateways []*k8s_networking_v1beta1.Gateway) []*k8s_networking_v1beta1.Gateway {
var gatewayAPIClassNames = map[string]string{}
for _, gwClass := range config.Get().ExternalServices.Istio.GatewayAPIClasses {
for _, gwClass := range GatewayAPIClasses() {
gatewayAPIClassNames[gwClass.ClassName] = gwClass.Name
}
if len(gatewayAPIClassNames) == 0 {
gatewayAPIClassNames["istio"] = "Istio"
}
filtered := []*k8s_networking_v1beta1.Gateway{}
for _, gw := range gateways {
if _, exist := gatewayAPIClassNames[string(gw.Spec.GatewayClassName)]; exist {
Expand Down
13 changes: 13 additions & 0 deletions kubernetes/istio.go
Original file line number Diff line number Diff line change
Expand Up @@ -898,3 +898,16 @@ func ClusterInfoFromIstiod(conf config.Config, k8s ClientInterface) (string, boo

return clusterName, gatewayToNamespace, nil
}

func GatewayAPIClasses() []config.GatewayAPIClass {
result := []config.GatewayAPIClass{}
for _, gwClass := range config.Get().ExternalServices.Istio.GatewayAPIClasses {
if gwClass.ClassName != "" && gwClass.Name != "" {
result = append(result, gwClass)
}
}
if len(result) == 0 {
result = append(result, config.GatewayAPIClass{Name: "Istio", ClassName: "istio"})
}
return result
}

0 comments on commit 405c6ef

Please sign in to comment.