ran pre-commit
This commit is contained in:
parent
f4aff5180e
commit
8aafaf1fba
@ -146,7 +146,7 @@ Similarly to Docker service discovery, there currently is no rigid ordering to d
|
||||
|
||||
## CRDs
|
||||
|
||||
Homepage also comes with Kubernetes CRDs for services. These CRDs have same structure and properties as regular service YAML definition, with added properties of `group`, `weight`, `podSelector` and `instances`, used as described above.
|
||||
Homepage also comes with Kubernetes CRDs for services. These CRDs have same structure and properties as regular service YAML definition, with added properties of `group`, `weight`, `podSelector` and `instances`, used as described above.
|
||||
|
||||
Compared to annotations, CRD approach can use Kubernetes secrets and configMaps to populate attributes of the `widget` object. To do this, instead of using the name, ex. `key`, use `keyFrom`, to match kubernetes standards. Then use either `secretKeyRef` or `configMapKeyRef` object, see example:
|
||||
|
||||
@ -161,18 +161,18 @@ metadata:
|
||||
spec:
|
||||
description: TV Show Management Application
|
||||
group: Media
|
||||
href: 'https://sonarr.example.org/'
|
||||
href: "https://sonarr.example.org/"
|
||||
icon: sonarr.svg
|
||||
widget:
|
||||
type: sonarr
|
||||
url: 'http://sonarr.media.svc.cluster.local:8989'
|
||||
url: "http://sonarr.media.svc.cluster.local:8989"
|
||||
keyFrom:
|
||||
secretKeyRef:
|
||||
key: SONARR_API_KEY
|
||||
name: arr-secrets
|
||||
```
|
||||
|
||||
Some attributes have values inferred from the definition itself, `app` is read from *app.kubernetes.io/name* annotation or metadata.name, namespace is also read from metadata.
|
||||
Some attributes have values inferred from the definition itself, `app` is read from _app.kubernetes.io/name_ annotation or metadata.name, namespace is also read from metadata.
|
||||
|
||||
For secrets and configMaps, if `namespace` is not specified in ref object, it assumes it's in the same namespace as CRD. If you want to specify a default namespace (for example for security reason when assigning secrets:read permission for only one namespace), you can specify `defaultSecretNamespace` and `defaultConfigMapNamespace` in `kubernetes.yaml` file.
|
||||
|
||||
@ -180,4 +180,4 @@ For secrets and configMaps, if `namespace` is not specified in ref object, it as
|
||||
---
|
||||
mode: cluster
|
||||
defaultSecretNamespace: homepage
|
||||
```
|
||||
```
|
||||
|
||||
@ -8,7 +8,7 @@ const logger = createLogger("kubernetes-widget");
|
||||
|
||||
export default async function handler(req, res) {
|
||||
try {
|
||||
const kc = makeKubeConfig(getKubernetesConfig())
|
||||
const kc = makeKubeConfig(getKubernetesConfig());
|
||||
if (!kc) {
|
||||
return res.status(500).send({
|
||||
error: "No kubernetes configuration",
|
||||
|
||||
@ -183,7 +183,6 @@ export async function servicesFromKubernetes() {
|
||||
const ANNOTATION_WIDGET_BASE = `${ANNOTATION_BASE}/widget.`;
|
||||
const { instanceName } = getSettings();
|
||||
|
||||
|
||||
try {
|
||||
const config = getKubernetesConfig();
|
||||
const kc = makeKubeConfig(config);
|
||||
@ -204,7 +203,7 @@ export async function servicesFromKubernetes() {
|
||||
|
||||
const traefikContainoExists = await checkCRD(kc, "ingressroutes.traefik.containo.us");
|
||||
const traefikExists = await checkCRD(kc, "ingressroutes.traefik.io");
|
||||
const homepageServiceExists = await checkCRD(kc, "homepageservices.gethomepage.dev")
|
||||
const homepageServiceExists = await checkCRD(kc, "homepageservices.gethomepage.dev");
|
||||
|
||||
const traefikIngressListContaino = await crd
|
||||
.listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes")
|
||||
@ -251,7 +250,7 @@ export async function servicesFromKubernetes() {
|
||||
return [];
|
||||
}
|
||||
|
||||
let homepageServices = []
|
||||
let homepageServices = [];
|
||||
if (homepageServiceExists) {
|
||||
homepageServices = await crd
|
||||
.listClusterCustomObject("gethomepage.dev", "v1", "homepageservices")
|
||||
@ -265,63 +264,75 @@ export async function servicesFromKubernetes() {
|
||||
);
|
||||
return [];
|
||||
});
|
||||
await Promise.all(homepageServices.items.map(async (service) => {
|
||||
const { spec, metadata } = service;
|
||||
// Enter default values from metadata or annotations
|
||||
spec.app = spec.app || metadata.annotations["app.kubernetes.io/name"] || metadata.name
|
||||
spec.namespace = spec.namespace || metadata.namespace
|
||||
spec.name = spec.name || metadata.name
|
||||
spec.weight = spec.weight || "0"
|
||||
spec.icon = spec.icon || ""
|
||||
spec.description = spec.description || ""
|
||||
// Parse values from secrets and configmaps in widget
|
||||
if (spec.widget) {
|
||||
const parsedWidget = {}
|
||||
await Promise.all(Object.keys(spec.widget).map(async key => {
|
||||
// To keep up with kubernetes standard valueFrom
|
||||
if (key.endsWith("From")) {
|
||||
if (spec.widget[key].secretKeyRef) {
|
||||
const { secretKeyRef } = spec.widget[key]
|
||||
const secret = await core.readNamespacedSecret(secretKeyRef.name, secretKeyRef.namespace || config.defaultSecretNamespace || metadata.namespace)
|
||||
const base64secret = secret.body.data[secretKeyRef.key]
|
||||
if (!base64secret) {
|
||||
logger.error(
|
||||
"Error getting secret value: Secret %s in namespace %s doesn't contain key %s",
|
||||
spec.widget[key].secretKeyRef.name,
|
||||
metadata.namespace,
|
||||
spec.widget[key].secretKeyRef.key,
|
||||
);
|
||||
return
|
||||
await Promise.all(
|
||||
homepageServices.items.map(async (service) => {
|
||||
const { spec, metadata } = service;
|
||||
// Enter default values from metadata or annotations
|
||||
spec.app = spec.app || metadata.annotations["app.kubernetes.io/name"] || metadata.name;
|
||||
spec.namespace = spec.namespace || metadata.namespace;
|
||||
spec.name = spec.name || metadata.name;
|
||||
spec.weight = spec.weight || "0";
|
||||
spec.icon = spec.icon || "";
|
||||
spec.description = spec.description || "";
|
||||
// Parse values from secrets and configmaps in widget
|
||||
if (spec.widget) {
|
||||
const parsedWidget = {};
|
||||
await Promise.all(
|
||||
Object.keys(spec.widget).map(async (key) => {
|
||||
// To keep up with kubernetes standard valueFrom
|
||||
if (key.endsWith("From")) {
|
||||
if (spec.widget[key].secretKeyRef) {
|
||||
const { secretKeyRef } = spec.widget[key];
|
||||
const secret = await core.readNamespacedSecret(
|
||||
secretKeyRef.name,
|
||||
secretKeyRef.namespace || config.defaultSecretNamespace || metadata.namespace,
|
||||
);
|
||||
const base64secret = secret.body.data[secretKeyRef.key];
|
||||
if (!base64secret) {
|
||||
logger.error(
|
||||
"Error getting secret value: Secret %s in namespace %s doesn't contain key %s",
|
||||
spec.widget[key].secretKeyRef.name,
|
||||
metadata.namespace,
|
||||
spec.widget[key].secretKeyRef.key,
|
||||
);
|
||||
return;
|
||||
}
|
||||
parsedWidget[key.substring(0, key.length - 4)] = Buffer.from(base64secret, "base64").toString(
|
||||
"utf8",
|
||||
);
|
||||
} else if (spec.widget[key].configMapKeyRef) {
|
||||
const { configMapKeyRef } = spec.widget[key];
|
||||
const configMap = await core.readNamespacedConfigMap(
|
||||
configMapKeyRef.name,
|
||||
configMapKeyRef.namespace || config.defaultConfigMapNamespace || metadata.namespace,
|
||||
);
|
||||
const configMapValue = configMap.body.data[configMapKeyRef.key];
|
||||
if (!configMapValue) {
|
||||
logger.error(
|
||||
"Error getting configMap value: ConfigMap %s in namespace %s doesn't contain key %s",
|
||||
spec.widget[key].configMapKey.name,
|
||||
metadata.namespace,
|
||||
spec.widget[key].configMapKey.key,
|
||||
);
|
||||
return;
|
||||
}
|
||||
parsedWidget[key.substring(0, key.length - 4)] = configMapValue;
|
||||
}
|
||||
} else {
|
||||
parsedWidget[key] = spec.widget[key];
|
||||
}
|
||||
parsedWidget[key.substring(0, key.length - 4)] = Buffer.from(base64secret, "base64").toString("utf8")
|
||||
} else if (spec.widget[key].configMapKeyRef) {
|
||||
const { configMapKeyRef } = spec.widget[key]
|
||||
const configMap = await core.readNamespacedConfigMap(configMapKeyRef.name, configMapKeyRef.namespace || config.defaultConfigMapNamespace || metadata.namespace)
|
||||
const configMapValue = configMap.body.data[configMapKeyRef.key]
|
||||
if (!configMapValue) {
|
||||
logger.error(
|
||||
"Error getting configMap value: ConfigMap %s in namespace %s doesn't contain key %s",
|
||||
spec.widget[key].configMapKey.name,
|
||||
metadata.namespace,
|
||||
spec.widget[key].configMapKey.key,
|
||||
);
|
||||
return
|
||||
}
|
||||
parsedWidget[key.substring(0, key.length - 4)] = configMapValue
|
||||
}
|
||||
} else {
|
||||
parsedWidget[key] = spec.widget[key]
|
||||
}
|
||||
}))
|
||||
spec.widget = parsedWidget
|
||||
}
|
||||
}))
|
||||
}),
|
||||
);
|
||||
spec.widget = parsedWidget;
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const services = [
|
||||
...homepageServices.items
|
||||
.filter(service => !service.spec.instances || service.spec.instances.includes(instanceName))
|
||||
.map(service => service.spec),
|
||||
.filter((service) => !service.spec.instances || service.spec.instances.includes(instanceName))
|
||||
.map((service) => service.spec),
|
||||
...ingressList.items
|
||||
.filter(
|
||||
(ingress) =>
|
||||
@ -377,7 +388,7 @@ export async function servicesFromKubernetes() {
|
||||
}
|
||||
|
||||
return constructedService;
|
||||
})
|
||||
}),
|
||||
];
|
||||
|
||||
const mappedServiceGroups = [];
|
||||
@ -403,7 +414,7 @@ export async function servicesFromKubernetes() {
|
||||
|
||||
return mappedServiceGroups;
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
console.log(e);
|
||||
if (e) logger.error(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user