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

feat: external service entry #747

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
63 changes: 43 additions & 20 deletions src/pepr/operator/controllers/istio/service-entry.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { UDSConfig } from "../../../config";
import { V1OwnerReference } from "@kubernetes/client-node";
import { UDSConfig } from "../../../config";
import {
Expose,
Gateway,
IstioServiceEntry,
IstioEndpoint,
IstioLocation,
IstioResolution,
IstioPort,
IstioEndpoint,
IstioResolution,
IstioServiceEntry,
} from "../../crd";
import { sanitizeResourceName } from "../utils";

/**
* Creates a ServiceEntry for each exposed service in the package
*
* @param pkg
* @param namespace
* @param expose - Expose configuration from the package
* @param namespace - The namespace of the service
* @param pkgName - The name of the package
* @param generation - The generation of the package
* @param ownerRefs - Owner references for the ServiceEntry
* @returns A ServiceEntry object for Istio configuration
*/
export function generateServiceEntry(
expose: Expose,
Expand All @@ -24,27 +28,39 @@ export function generateServiceEntry(
generation: string,
ownerRefs: V1OwnerReference[],
) {
const { gateway = Gateway.Tenant, host } = expose;
// Destructure fields from 'expose', with default values for gateway and location
const { gateway = Gateway.Tenant, host, location = "MESH_INTERNAL" } = expose;

// Generate a sanitized name for the ServiceEntry
const name = generateSEName(pkgName, expose);

// For the admin gateway, we need to add the path prefix
// Construct the domain based on the gateway type and UDS configuration
// If the gateway is 'admin', prefix the domain with 'admin.', otherwise use the standard domain
const domain = (gateway === Gateway.Admin ? "admin." : "") + UDSConfig.domain;

// Append the domain to the host
const fqdn = `${host}.${domain}`;
// Determine the Fully Qualified Domain Name (FQDN) for the service
// For internal services (MESH_INTERNAL), append the domain to the host
// For external services (MESH_EXTERNAL), use the host directly as provided in the Expose configuration
const fqdn = location === "MESH_INTERNAL" ? `${host}.${domain}` : host;

// Define the service port for HTTPS traffic
const serviceEntryPort: IstioPort = {
name: "https",
number: 443,
protocol: "HTTPS",
};

// Define the service entry endpoint
// If the service is external (MESH_EXTERNAL), no specific endpoint is needed (DNS-based resolution)
// If internal, map the gateway (admin, passthrough, or tenant) to the ServiceEntry using the gateway-specific address
const serviceEntryEndpoint: IstioEndpoint = {
// Map the gateway (admin, passthrough or tenant) to the ServiceEntry
address: `${gateway}-ingressgateway.istio-${gateway}-gateway.svc.cluster.local`,
address:
location === "MESH_EXTERNAL"
? undefined
: `${gateway}-ingressgateway.istio-${gateway}-gateway.svc.cluster.local`,
};

// Construct the ServiceEntry payload object
const payload: IstioServiceEntry = {
metadata: {
name,
Expand All @@ -53,26 +69,33 @@ export function generateServiceEntry(
"uds/package": pkgName,
"uds/generation": generation,
},
// Use the CR as the owner ref for each ServiceEntry
// Use the Custom Resource (CR) as the owner reference for each ServiceEntry
ownerReferences: ownerRefs,
},
spec: {
// Append the UDS Domain to the host
hosts: [fqdn],
location: IstioLocation.MeshInternal,
resolution: IstioResolution.DNS,
ports: [serviceEntryPort],
endpoints: [serviceEntryEndpoint],
hosts: [fqdn], // The host(s) this ServiceEntry applies to
location: location as IstioLocation, // Set the service location (internal or external)
resolution: IstioResolution.DNS, // Set the resolution type based on the service location
ports: [serviceEntryPort], // Define ports for the service
endpoints: location === "MESH_EXTERNAL" ? [] : [serviceEntryEndpoint], // Define endpoints if internal
},
};

return payload;
}

/**
* Generates a sanitized name for the ServiceEntry
*
* @param pkgName - The name of the package
* @param expose - Expose configuration
* @returns A sanitized resource name suitable for use in Kubernetes metadata
*/
export function generateSEName(pkgName: string, expose: Expose) {
const { gateway = Gateway.Tenant, host } = expose;

// Ensure the resource name is valid
// Combine package name, gateway, and host to create a unique resource name
// Sanitize the name to ensure it is a valid Kubernetes resource name
const name = sanitizeResourceName(`${pkgName}-${gateway}-${host}`);

return name;
Expand Down
12 changes: 12 additions & 0 deletions src/pepr/operator/crd/generated/package-v1alpha1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ export interface Expose {
* The hostname to expose the service on
*/
host: string;
/**
* Specifies whether the service is MESH_INTERNAL or MESH_EXTERNAL
*/
location?: Location;
/**
* Match the incoming request based on custom rules. Not permitted when using the
* passthrough gateway.
Expand Down Expand Up @@ -458,6 +462,14 @@ export enum Gateway {
Tenant = "tenant",
}

/**
* Specifies whether the service is MESH_INTERNAL or MESH_EXTERNAL
*/
export enum Location {
MeshExternal = "MESH_EXTERNAL",
MeshInternal = "MESH_INTERNAL",
}

export interface ExposeMatch {
/**
* Flag to specify whether the URI matching should be case-insensitive.
Expand Down
6 changes: 6 additions & 0 deletions src/pepr/operator/crd/sources/package/v1alpha1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ const expose = {
type: "string",
},
},
location: {
description: "Specifies whether the service is MESH_INTERNAL or MESH_EXTERNAL",
enum: ["MESH_INTERNAL", "MESH_EXTERNAL"],
type: "string",
default: "MESH_INTERNAL",
},
},
} as V1JSONSchemaProps,
} as V1JSONSchemaProps;
Expand Down
Loading