Skip to content
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

Gateway API class selector in K8s Gateway Istio config wizard #6585

Merged
merged 2 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trivial - alphabetized out of order in a few places (not a blocker, can fix in some other PR)

'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 && (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess another option would be to always display this so that the user can see the set value. But this approach is fine as well, not a blocker.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the Gateway Classes available in Debug info.

<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
}