-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
274 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { K8s, Log } from "pepr"; | ||
|
||
import { UDSConfig } from "../../../config"; | ||
import { Expose, Gateway, IstioServiceEntry, IstioLocation, IstioResolution, IstioPort, IstioEndpoint, UDSPackage } from "../../crd"; | ||
import { getOwnerRef, sanitizeResourceName } from "../utils"; | ||
|
||
/** | ||
* Creates a ServiceEntry for each exposed service in the package | ||
* | ||
* @param pkg | ||
* @param namespace | ||
*/ | ||
export async function serviceEntry(pkg: UDSPackage, namespace: string) { | ||
const pkgName = pkg.metadata!.name!; | ||
const generation = (pkg.metadata?.generation ?? 0).toString(); | ||
|
||
// Get the list of exposed services | ||
const exposeList = pkg.spec?.network?.expose ?? []; | ||
|
||
// Track which ServiceEntries we've created | ||
const serviceEntryNames: Map<string, boolean> = new Map(); | ||
|
||
// Iterate over each exposed service | ||
for (const expose of exposeList) { | ||
const { gateway = Gateway.Tenant, host } = expose; | ||
|
||
const name = generateSEName(pkg, expose); | ||
|
||
// If we have already made a ServiceEntry with this name, skip (i.e. if advancedHTTP was used) | ||
if (serviceEntryNames.get(name)) { | ||
continue | ||
} | ||
|
||
// For the admin gateway, we need to add the path prefix | ||
const domain = (gateway === Gateway.Admin ? "admin." : "") + UDSConfig.domain; | ||
|
||
// Append the domain to the host | ||
const fqdn = `${host}.${domain}`; | ||
|
||
const serviceEntryPort: IstioPort = { | ||
name: "https", | ||
number: 443, | ||
protocol: "HTTPS", | ||
} | ||
|
||
const serviceEntryEndpoint: IstioEndpoint = { | ||
// Map the gateway (admin, passthrough or tenant) to the ServiceEntry | ||
address: `${gateway}-ingressgateway.istio-${gateway}-gateway.svc.cluster.local` | ||
} | ||
|
||
const payload: IstioServiceEntry = { | ||
metadata: { | ||
name, | ||
namespace, | ||
labels: { | ||
"uds/package": pkgName, | ||
"uds/generation": generation, | ||
}, | ||
// Use the CR as the owner ref for each ServiceEntry | ||
ownerReferences: getOwnerRef(pkg), | ||
}, | ||
spec: { | ||
// Append the UDS Domain to the host | ||
hosts: [fqdn], | ||
location: IstioLocation.MeshInternal, | ||
resolution: IstioResolution.DNS, | ||
ports: [serviceEntryPort], | ||
endpoints: [serviceEntryEndpoint], | ||
}, | ||
}; | ||
|
||
|
||
Log.debug(payload, `Applying ServiceEntry ${payload.metadata?.name}`); | ||
|
||
// Apply the ServiceEntry and force overwrite any existing policy | ||
await K8s(IstioServiceEntry).Apply(payload, { force: true }); | ||
|
||
serviceEntryNames.set(name, true) | ||
} | ||
|
||
// Get all related ServiceEntries in the namespace | ||
const serviceEntries = await K8s(IstioServiceEntry) | ||
.InNamespace(namespace) | ||
.WithLabel("uds/package", pkgName) | ||
.Get(); | ||
|
||
// Find any orphaned ServiceEntries (not matching the current generation) | ||
const orphanedSE = serviceEntries.items.filter( | ||
vs => vs.metadata?.labels?.["uds/generation"] !== generation, | ||
); | ||
|
||
// Delete any orphaned ServiceEntries | ||
for (const vs of orphanedSE) { | ||
Log.debug(vs, `Deleting orphaned ServiceEntry ${vs.metadata!.name}`); | ||
await K8s(IstioServiceEntry).Delete(vs); | ||
} | ||
} | ||
|
||
export function generateSEName(pkg: UDSPackage, expose: Expose) { | ||
const { gateway = Gateway.Tenant, host, port, service, description } = expose; | ||
|
||
// Ensure the resource name is valid | ||
const nameSuffix = description || `${host}-${port}-${service}`; | ||
const name = sanitizeResourceName(`${pkg.metadata!.name}-${gateway}-${nameSuffix}`); | ||
|
||
return name; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
141 changes: 141 additions & 0 deletions
141
src/pepr/operator/crd/generated/istio/serviceentry-v1beta1.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
// This file is auto-generated by kubernetes-fluent-client, do not edit manually | ||
|
||
import { GenericKind, RegisterKind } from "kubernetes-fluent-client"; | ||
|
||
export class ServiceEntry extends GenericKind { | ||
/** | ||
* Configuration affecting service registry. See more details at: | ||
* https://istio.io/docs/reference/config/networking/service-entry.html | ||
*/ | ||
spec?: Spec; | ||
status?: { [key: string]: any }; | ||
} | ||
|
||
/** | ||
* Configuration affecting service registry. See more details at: | ||
* https://istio.io/docs/reference/config/networking/service-entry.html | ||
*/ | ||
export interface Spec { | ||
/** | ||
* The virtual IP addresses associated with the service. | ||
*/ | ||
addresses?: string[]; | ||
/** | ||
* One or more endpoints associated with the service. | ||
*/ | ||
endpoints?: Endpoint[]; | ||
/** | ||
* A list of namespaces to which this service is exported. | ||
*/ | ||
exportTo?: string[]; | ||
/** | ||
* The hosts associated with the ServiceEntry. | ||
*/ | ||
hosts: string[]; | ||
/** | ||
* Specify whether the service should be considered external to the mesh or part of the mesh. | ||
*/ | ||
location?: Location; | ||
/** | ||
* The ports associated with the external service. | ||
*/ | ||
ports?: Port[]; | ||
/** | ||
* Service resolution mode for the hosts. | ||
*/ | ||
resolution?: Resolution; | ||
/** | ||
* If specified, the proxy will verify that the server certificate's subject alternate name | ||
* matches one of the specified values. | ||
*/ | ||
subjectAltNames?: string[]; | ||
/** | ||
* Applicable only for MESH_INTERNAL services. | ||
*/ | ||
workloadSelector?: WorkloadSelector; | ||
} | ||
|
||
export interface Endpoint { | ||
/** | ||
* Address associated with the network endpoint without the port. | ||
*/ | ||
address?: string; | ||
/** | ||
* One or more labels associated with the endpoint. | ||
*/ | ||
labels?: { [key: string]: string }; | ||
/** | ||
* The locality associated with the endpoint. | ||
*/ | ||
locality?: string; | ||
/** | ||
* Network enables Istio to group endpoints resident in the same L3 domain/network. | ||
*/ | ||
network?: string; | ||
/** | ||
* Set of ports associated with the endpoint. | ||
*/ | ||
ports?: { [key: string]: number }; | ||
/** | ||
* The service account associated with the workload if a sidecar is present in the workload. | ||
*/ | ||
serviceAccount?: string; | ||
/** | ||
* The load balancing weight associated with the endpoint. | ||
*/ | ||
weight?: number; | ||
} | ||
|
||
/** | ||
* Specify whether the service should be considered external to the mesh or part of the mesh. | ||
*/ | ||
export enum Location { | ||
MeshExternal = "MESH_EXTERNAL", | ||
MeshInternal = "MESH_INTERNAL", | ||
} | ||
|
||
export interface Port { | ||
/** | ||
* Label assigned to the port. | ||
*/ | ||
name: string; | ||
/** | ||
* A valid non-negative integer port number. | ||
*/ | ||
number: number; | ||
/** | ||
* The protocol exposed on the port. | ||
*/ | ||
protocol?: string; | ||
/** | ||
* The port number on the endpoint where the traffic will be received. | ||
*/ | ||
targetPort?: number; | ||
} | ||
|
||
/** | ||
* Service resolution mode for the hosts. | ||
*/ | ||
export enum Resolution { | ||
DNS = "DNS", | ||
DNSRoundRobin = "DNS_ROUND_ROBIN", | ||
None = "NONE", | ||
Static = "STATIC", | ||
} | ||
|
||
/** | ||
* Applicable only for MESH_INTERNAL services. | ||
*/ | ||
export interface WorkloadSelector { | ||
/** | ||
* One or more labels that indicate a specific set of pods/VMs on which the configuration | ||
* should be applied. | ||
*/ | ||
labels?: { [key: string]: string }; | ||
} | ||
|
||
RegisterKind(ServiceEntry, { | ||
group: "networking.istio.io", | ||
version: "v1beta1", | ||
kind: "ServiceEntry", | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters