Skip to content

Commit

Permalink
refactor(k8s): shorten default namespace names
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

After updating, any project that doesn't have an explicitly
configured namespace will be installed into a new namespace,
and the old namespace needs to be manually removed.
  • Loading branch information
edvald committed Jan 14, 2019
1 parent 4669d42 commit 15aa5de
Show file tree
Hide file tree
Showing 16 changed files with 52 additions and 46 deletions.
8 changes: 4 additions & 4 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ project:
{}

# Valid RFC1035/RFC1123 (DNS) label (may contain lowercase letters, numbers and dashes, must
# start with a letter, and cannot end with a dash) and additionally cannot contain
# consecutive dashes, or be longer than 63 characters.
# start with a letter, and cannot end with a dash), cannot contain consecutive dashes or
# start with `garden`, or be longer than 63 characters.
#
# Required.
name:
Expand Down Expand Up @@ -523,8 +523,8 @@ module:
#
# Optional.
- # Valid RFC1035/RFC1123 (DNS) label (may contain lowercase letters, numbers and dashes, must
# start with a letter, and cannot end with a dash) and additionally cannot contain
# consecutive dashes, or be longer than 63 characters.
# start with a letter, and cannot end with a dash), cannot contain consecutive dashes or
# start with `garden`, or be longer than 63 characters.
#
# Required.
name:
Expand Down
4 changes: 2 additions & 2 deletions garden-service/src/commands/create/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
dumpConfig,
} from "./helpers"
import { prompts } from "./prompts"
import { validate, joiIdentifier } from "../../config/common"
import { validate, joiUserIdentifier } from "../../config/common"
import { NewModuleOpts } from "./project"
import { configSchema } from "../../config/base"

Expand Down Expand Up @@ -77,7 +77,7 @@ export class CreateModuleCommand extends Command<Args, Opts> {
const moduleRoot = join(garden.projectRoot, (args["module-dir"] || "").trim())
const moduleName = validate(
opts.name || basename(moduleRoot),
joiIdentifier(),
joiUserIdentifier(),
{ context: "module name" },
)

Expand Down
4 changes: 2 additions & 2 deletions garden-service/src/commands/create/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
ProjectTemplate,
} from "./config-templates"
import { getChildDirNames } from "../../util/util"
import { validate, joiIdentifier } from "../../config/common"
import { validate, joiUserIdentifier } from "../../config/common"
import { configSchema } from "../../config/base"

const flatten = (acc, val) => acc.concat(val)
Expand Down Expand Up @@ -108,7 +108,7 @@ export class CreateProjectCommand extends Command<Args, Opts> {
const moduleParentDirs = await Bluebird.map(opts["module-dirs"] || [], (dir: string) => resolve(projectRoot, dir))
const projectName = validate(
opts.name || basename(projectRoot),
joiIdentifier(),
joiUserIdentifier(),
{ context: "project name" },
)

Expand Down
4 changes: 2 additions & 2 deletions garden-service/src/commands/create/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as inquirer from "inquirer"
import * as Joi from "joi"
import chalk from "chalk"

import { joiIdentifier } from "../../config/common"
import { joiUserIdentifier } from "../../config/common"
import { ModuleType } from "./config-templates"

export interface ModuleTypeChoice extends inquirer.objects.ChoiceOption {
Expand Down Expand Up @@ -88,7 +88,7 @@ async function addModule(addModuleMessage: string): Promise<ModuleTypeAndName> {
type: "input",
validate: input => {
try {
Joi.attempt(input.trim(), joiIdentifier())
Joi.attempt(input.trim(), joiUserIdentifier())
} catch (err) {
return `Invalid module name, please try again\nError: ${err.message}`
}
Expand Down
8 changes: 4 additions & 4 deletions garden-service/src/config-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { resolve } from "path"
import { ensureFile, readFile } from "fs-extra"
import { get, isPlainObject, unset } from "lodash"

import { joiIdentifier, Primitive, validate, joiArray } from "./config/common"
import { Primitive, validate, joiArray, joiUserIdentifier } from "./config/common"
import { LocalConfigError } from "./exceptions"
import { dumpYaml } from "./util/util"
import { GARDEN_DIR_NAME, LOCAL_CONFIG_FILENAME } from "./constants"
Expand Down Expand Up @@ -175,14 +175,14 @@ export interface LocalConfig {

const kubernetesLocalConfigSchema = Joi.object()
.keys({
"username": joiIdentifier().allow("").optional(),
"previous-usernames": Joi.array().items(joiIdentifier()).optional(),
"username": joiUserIdentifier().allow("").optional(),
"previous-usernames": Joi.array().items(joiUserIdentifier()).optional(),
})
.meta({ internal: true })

const linkedSourceSchema = Joi.object()
.keys({
name: joiIdentifier(),
name: joiUserIdentifier(),
path: Joi.string(),
})
.meta({ internal: true })
Expand Down
3 changes: 2 additions & 1 deletion garden-service/src/config/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
joiVariables,
PrimitiveMap,
joiRepositoryUrl,
joiUserIdentifier,
} from "./common"
import { TestConfig, TestSpec } from "./test"
import { TaskConfig, TaskSpec } from "./task"
Expand Down Expand Up @@ -77,7 +78,7 @@ export const baseModuleSpecSchema = Joi.object()
.required()
.description("The type of this module.")
.example("container"),
name: joiIdentifier()
name: joiUserIdentifier()
.required()
.description("The name of this module.")
.example("my-sweet-module"),
Expand Down
5 changes: 3 additions & 2 deletions garden-service/src/config/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
joiVariables,
Primitive,
joiRepositoryUrl,
joiUserIdentifier,
} from "./common"

export interface ProviderConfig {
Expand Down Expand Up @@ -74,7 +75,7 @@ export interface SourceConfig {

export const projectSourceSchema = Joi.object()
.keys({
name: joiIdentifier()
name: joiUserIdentifier()
.required()
.description("The name of the source to import"),
repositoryUrl: joiRepositoryUrl()
Expand Down Expand Up @@ -131,7 +132,7 @@ export const projectSchema = Joi.object()
.description(
"Default environment settings. These are inherited (but can be overridden) by each configured environment.",
),
environments: joiArray(environmentConfigSchema.keys({ name: joiIdentifier().required() }))
environments: joiArray(environmentConfigSchema.keys({ name: joiUserIdentifier().required() }))
.unique("name")
.default(() => ({ ...defaultEnvironments }), safeDump(defaultEnvironments))
.description("A list of environments to configure for the project.")
Expand Down
4 changes: 2 additions & 2 deletions garden-service/src/config/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import deline = require("deline")
import * as Joi from "joi"
import { PrimitiveMap, joiIdentifier, joiIdentifierMap, joiPrimitive, joiArray } from "./common"
import { PrimitiveMap, joiIdentifier, joiIdentifierMap, joiPrimitive, joiArray, joiUserIdentifier } from "./common"

export interface ServiceSpec { }

Expand All @@ -22,7 +22,7 @@ export const serviceOutputsSchema = joiIdentifierMap(joiPrimitive())

export const baseServiceSchema = Joi.object()
.keys({
name: joiIdentifier().required(),
name: joiUserIdentifier().required(),
dependencies: joiArray(joiIdentifier())
.description(deline`
The names of any services that this service depends on at runtime, and the names of any
Expand Down
9 changes: 3 additions & 6 deletions garden-service/src/config/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@

import deline = require("deline")
import * as Joi from "joi"
import {
joiArray,
joiIdentifier,
} from "./common"
import { joiArray, joiUserIdentifier } from "./common"

export interface TaskSpec { }

Expand All @@ -24,7 +21,7 @@ export interface BaseTaskSpec extends TaskSpec {

export const baseTaskSpecSchema = Joi.object()
.keys({
name: joiIdentifier()
name: joiUserIdentifier()
.required()
.description("The name of the task."),
description: Joi.string().optional()
Expand Down Expand Up @@ -58,7 +55,7 @@ export const taskConfigSchema = baseTaskSpecSchema
export const taskSchema = Joi.object()
.options({ presence: "required" })
.keys({
name: joiIdentifier()
name: joiUserIdentifier()
.description("The name of the task."),
description: Joi.string().optional()
.description("A description of the task."),
Expand Down
4 changes: 2 additions & 2 deletions garden-service/src/config/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import deline = require("deline")
import * as Joi from "joi"
import {
joiArray,
joiIdentifier,
joiUserIdentifier,
} from "./common"

export interface TestSpec { }
Expand All @@ -23,7 +23,7 @@ export interface BaseTestSpec extends TestSpec {

export const baseTestSpecSchema = Joi.object()
.keys({
name: joiIdentifier()
name: joiUserIdentifier()
.required()
.description("The name of the test."),
dependencies: joiArray(Joi.string())
Expand Down
3 changes: 1 addition & 2 deletions garden-service/src/plugins/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { Module } from "../types/module"
import {
absolutePathRegex,
joiEnvVars,
joiIdentifier,
joiUserIdentifier,
joiArray,
validate,
Expand Down Expand Up @@ -168,7 +167,7 @@ const healthCheckSchema = Joi.object()

export const portSchema = Joi.object()
.keys({
name: joiIdentifier()
name: joiUserIdentifier()
.required()
.description("The name of the port (used when referencing the port elsewhere in the service configuration)."),
protocol: Joi.string()
Expand Down
10 changes: 5 additions & 5 deletions garden-service/src/plugins/kubernetes/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import {
PluginActionParamsBase,
} from "../../types/plugin/params"
import { sleep } from "../../util/util"
import { joiIdentifier } from "../../config/common"
import { joiUserIdentifier } from "../../config/common"
import { KubeApi } from "./api"
import {
getAppNamespace,
getMetadataNamespace,
getAllGardenNamespaces,
getAllNamespaces,
} from "./namespace"
import { KUBECTL_DEFAULT_TIMEOUT, kubectl } from "./kubectl"
import { name as providerName } from "./kubernetes"
Expand Down Expand Up @@ -179,7 +179,7 @@ export async function cleanupEnvironment({ ctx, log }: CleanupEnvironmentParams)
await api.core.deleteNamespace(namespace, <any>{})
} catch (err) {
entry.setError(err.message)
const availableNamespaces = await getAllGardenNamespaces(api)
const availableNamespaces = await getAllNamespaces(api)
throw new NotFoundError(err, { namespace, availableNamespaces })
}

Expand All @@ -190,7 +190,7 @@ export async function cleanupEnvironment({ ctx, log }: CleanupEnvironmentParams)
while (true) {
await sleep(2000)

const nsNames = await getAllGardenNamespaces(api)
const nsNames = await getAllNamespaces(api)
if (!nsNames.includes(namespace)) {
entry.setSuccess()
break
Expand Down Expand Up @@ -249,7 +249,7 @@ async function login({ ctx, log }: PluginActionParamsBase) {
message: "Enter username",
validate: input => {
try {
Joi.attempt(input.trim(), joiIdentifier())
Joi.attempt(input.trim(), joiUserIdentifier())
} catch (err) {
return `Invalid username, please try again\nError: ${err.message}`
}
Expand Down
11 changes: 6 additions & 5 deletions garden-service/src/plugins/kubernetes/kubernetes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,6 @@ export const kubernetesConfigBase = providerConfigBaseSchema
"is available for a configured hostname.",
),
imagePullSecrets: imagePullSecretsSchema,
namespace: Joi.string()
.description(
"Specify which namespace to deploy services to (auto-generated by default). " +
"Note that the framework generates other namespaces as well with this name as a prefix.",
),
tlsCertificates: joiArray(tlsCertificateSchema)
.unique("name")
.description("One or more certificates to use for ingress."),
Expand All @@ -149,6 +144,12 @@ const configSchema = kubernetesConfigBase
ingressHttpsPort: Joi.number()
.default(443)
.description("The external HTTPS port of the cluster's ingress controller."),
namespace: Joi.string()
.default(undefined, "<username>--<project name>")
.description(
"Specify which namespace to deploy services to (defaults to <username>--<project name>). " +
"Note that the framework generates other namespaces as well with this name as a prefix.",
),
_system: Joi.any().meta({ internal: true }),
})

Expand Down
8 changes: 7 additions & 1 deletion garden-service/src/plugins/kubernetes/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ export interface LocalKubernetesConfig extends KubernetesBaseConfig {

const configSchema = kubernetesConfigBase
.keys({
namespace: Joi.string()
.default(undefined, "<project name>")
.description(
"Specify which namespace to deploy services to (defaults to the project name). " +
"Note that the framework generates other namespaces as well with this name as a prefix.",
),
ingressHostname: Joi.string()
.description("The hostname of the cluster's ingress controller."),
_system: Joi.any().meta({ internal: true }),
Expand Down Expand Up @@ -129,7 +135,6 @@ export async function gardenPlugin({ projectName, config, log }): Promise<Garden
name: config.name,
context,
defaultHostname,
defaultUsername: "default",
deploymentRegistry: {
hostname: "foo.garden", // this is not used by this plugin, but required by the base plugin
namespace: "_",
Expand All @@ -139,6 +144,7 @@ export async function gardenPlugin({ projectName, config, log }): Promise<Garden
ingressHttpPort: 80,
ingressHttpsPort: 443,
ingressClass: "nginx",
namespace: config.namespace || projectName,
tlsCertificates: config.tlsCertificates,
_system: config._system,
_systemServices: systemServices,
Expand Down
9 changes: 5 additions & 4 deletions garden-service/src/plugins/kubernetes/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ export async function getNamespace(
): Promise<string> {
let namespace

if (provider.config.namespace) {
if (provider.config.namespace !== undefined) {
namespace = provider.config.namespace
} else {
// Note: The local-kubernetes always defines a namespace name, so this logic only applies to the kubernetes provider
// TODO: Move this logic out to the kubernetes plugin init/validation
const localConfig = await ctx.localConfigStore.get()
const k8sConfig = localConfig.kubernetes || {}
let { username, ["previous-usernames"]: previousUsernames } = k8sConfig
Expand All @@ -66,7 +68,7 @@ export async function getNamespace(
)
}

namespace = `garden--${username}--${ctx.projectName}`
namespace = `${username}--${ctx.projectName}`
}

if (suffix) {
Expand All @@ -89,9 +91,8 @@ export function getMetadataNamespace(ctx: PluginContext, provider: KubernetesPro
return getNamespace({ ctx, provider, suffix: "metadata" })
}

export async function getAllGardenNamespaces(api: KubeApi): Promise<string[]> {
export async function getAllNamespaces(api: KubeApi): Promise<string[]> {
const allNamespaces = await api.core.listNamespace()
return allNamespaces.body.items
.map(n => n.metadata.name)
.filter(n => n.startsWith("garden--"))
}
4 changes: 2 additions & 2 deletions garden-service/src/types/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import * as Joi from "joi"
import { getEnvVarName } from "../util/util"
import { PrimitiveMap, joiIdentifier, joiEnvVars, joiIdentifierMap, joiPrimitive } from "../config/common"
import { PrimitiveMap, joiEnvVars, joiIdentifierMap, joiPrimitive, joiUserIdentifier } from "../config/common"
import { Module, getModuleKey } from "./module"
import { serviceOutputsSchema, ServiceConfig, serviceConfigSchema } from "../config/service"
import { validate } from "../config/common"
Expand All @@ -29,7 +29,7 @@ export interface Service<M extends Module = Module> {
export const serviceSchema = Joi.object()
.options({ presence: "required" })
.keys({
name: joiIdentifier()
name: joiUserIdentifier()
.description("The name of the service."),
module: Joi.object().unknown(true), // This causes a stack overflow: Joi.lazy(() => moduleSchema),
config: serviceConfigSchema,
Expand Down

0 comments on commit 15aa5de

Please sign in to comment.