Skip to content
Open
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
199 changes: 199 additions & 0 deletions core/src/main/resources/nelson/magnetar.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
job "{{unit_name}}" {
{{#schedule}}
type = "batch"
{{/schedule}}
{{^schedule}}
type = "service"
{{/schedule}}

region = "us"
datacenters = ["{{datacenter}}"]

{{!- todo support time zone for predefined expressions }}
{{#schedule}}
periodic {
cron = "{{schedule}}"
prohibit_overlap = true
}
{{/schedule}}

all_at_once = false

group "{{unit_name}}" {
{{#desired_instances}}
count = {{desired_instances}}
{{/desired_instances}}
{{^desired_instances}}
count = 1
{{/desired_instances}}

{{#ephemeral_disks_list}}
ephemeral_disk {
migrate = {{ephemeral_disk_migrate}}
size = "{{ephemeral_disk_size}}"
sticky = {{ephemeral_disk_sticky}}
}
{{/ephemeral_disks_list}}

restart {
{{#restart_interval}}
interval = "{{restart_interval}}"
{{/restart_interval}}
{{^restart_interval}}
interval = "5m"
{{/restart_interval}}
{{#retries}}
attempts = {{retries}}
{{/retries}}
{{^retries}}
attempts = 3
{{/retries}}
{{#restart_delay}}
delay = "{{restart_delay}}"
{{/restart_delay}}
{{^restart_delay}}
delay = "15s"
{{/restart_delay}}
{{#restart_mode}}
mode = "{{restart_mode}}"
{{/restart_mode}}
{{^restart_mode}}
{{#schedule}}
mode = "fail"
{{/schedule}}
{{^schedule}}
mode = "delay"
{{/schedule}}
{{/restart_mode}}
}

task "{{unit_name}}" {
driver = "docker"

env {
{{#envvars}}
{{#envvars_list}}
"{{envvar_name}}" = "{{envvar_value}}"
{{/envvars_list}}
{{/envvars}}
}

config {
image = "{{image}}"

network_mode = "{{docker_network_mode}}"

volumes = [
{{#empty_volumes_list}}
"{{empty_volume_mount_name}}:{{empty_volume_mount_path}}"
{{/empty_volumes_list}}
]

auth {
{{#docker_username}}
username = "{{docker_username}}"
{{/docker_username}}
{{#docker_password}}
password = "{{docker_password}}"
{{/docker_password}}
{{#docker_server_address}}
server_address = "{{docker_server_address}}"
{{/docker_server_address}}
}
auth_soft_fail = true

labels {
stack_name = "{{stack_name}}"
unit_name = "{{unit_name}}"
version = "{{version}}"
nelson = "true"
}
}

service {
tags = [{{tags}}]

{{#health_checks}}
check {
type = "{{health_check_type}}" {{! todo support other check types }}
protocol = "{{health_check_protocol}}"
tls_skip_verify = {{health_check_tls_skip_verify}}
name = "{{health_check_name}}"
port = "{{health_check_port_ref}}" {{! todo method would be useful too; i use HEAD often }}
path = "{{health_check_path}}"
interval = "{{health_check_interval}}"
timeout = "{{health_check_timeout}}"

{{#health_check_header}}
header {
{{health_check_header_name}} = ["{{health_check_header_value}}"]
}
{{/health_check_header}}
}
{{/health_checks}}
}

vault {
policies = [
{{#vault_policies}}
"{{vault_policy_name}}"
{{/vault_policies}}
]
env = true
{{#vault_change_mode}}
change_mode = "{{vault_change_mode}}"
{{/vault_change_mode}}
{{^vault_change_mode}}
change_mode = "restart"
{{/vault_change_mode}}
{{#vault_change_signal}}
change_signal = "{{vault_change_signal}}"
{{/vault_change_signal}}
{{^vault_change_signal}}
change_signal = "{{vault_change_signal}}"
{{/vault_change_signal}}
}

resources {
{{#cpu_limit}}
cpu = {{cpu_limit}}
{{/cpu_limit}}
{{^cpu_limit}}
cpu = 10
{{/cpu_limit}}
{{#memory_limit}}
memory = {{memory_limit}}
{{/memory_limit}}
{{^memory_limit}}
memory = 500
{{/memory_limit}}

network {
mbits = 1
{{#ports}}
{{#ports_list}}
{{#port_number}}
port "{{port_name}}" {
static = "{{port_number}}"
}
{{/port_number}}
{{^port_number}}
port "{{port_name}}" {}
{{/port_number}}
{{/ports_list}}
{{/ports}}
}
}
}
}

meta {
name = "{{stack_name}}"
namespace = "{{namespace}}"
stackName = "{{stack_name}}"
unitName = "{{unit_name}}"
version = "{{version}}"
nelson = "true"
plan_meta = "{{nelson_unit_metadata}}"
}
}
35 changes: 27 additions & 8 deletions core/src/main/scala/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ final case class DockerConfig(
verifyTLS: Boolean
)

final case class DockerCreds(
dockerRepoUser: String,
dockerRepoPassword: String
)

final case class NomadConfig(
applicationPrefix: Option[String],
requiredServiceTags: Option[List[String]]
Expand Down Expand Up @@ -536,16 +541,28 @@ object Config {
stg: StoreOp ~> IO,
logger: LoggingOp ~> IO): IO[List[Datacenter]] = {

def readDocker(kfg: KConfig): Infrastructure.Docker = {

val creds =
(kfg.lookup[String]("docker.user"),
kfg.lookup[String]("docker.password")
).mapN((a,b) => Docker.Credentials(a,b))

/*
If a datacenter specific registry isn't specified fall back to Nelson's publish registry
*/
val registry = kfg.lookup[String]("docker.registry") getOrElse kfg.require[String]("docker-registry")

Infrastructure.Docker(registry, creds)
}

def readNomadInfrastructure(kfg: KConfig): Option[Infrastructure.Nomad] = {
(kfg.lookup[String]("endpoint"),
kfg.lookup[Duration]("timeout"),
kfg.lookup[String]("docker.user"),
kfg.lookup[String]("docker.password"),
kfg.lookup[String]("docker.host"),
kfg.lookup[Int]("mhz-per-cpu")
).mapN((a,b,c,d,e,f) => {
).mapN((a,b,c) => {
val uri = Uri.fromString(a).toOption.yolo(s"nomad.endpoint -- $a -- is an invalid Uri")
Infrastructure.Nomad(uri,b,c,d,e,f)
Infrastructure.Nomad(uri,b,readDocker(kfg),c)
})
}

Expand All @@ -559,7 +576,7 @@ object Config {
} yield Infrastructure.Kubernetes(mode, timeout)

def readNomadScheduler(kfg: KConfig): IO[SchedulerOp ~> IO] =
readNomadInfrastructure(kfg) match {
readNomadInfrastructure(kfg.subconfig("infrastructure.nomad")) match {
case Some(n) => http4sClient(n.timeout).map(client => new scheduler.NomadHttp(nomadcfg, n, client, schedulerPool, ec))
case None => IO.raiseError(new IllegalArgumentException("Unable to parse the nomad scheduler configuration"))
}
Expand Down Expand Up @@ -629,7 +646,9 @@ object Config {
withKubectl((kubectl, timeout) =>
IO.pure(new KubernetesShell(kubectl, timeout, ec, schedulerPool)))
}
case Some("nomad") => IO.raiseError(NomadNotImplemented)
case Some("nomad") => {
readNomadScheduler(kfg)
}
case _ => IO.raiseError(new IllegalArgumentException("At least one scheduler must be defined per datacenter"))
}

Expand Down Expand Up @@ -675,7 +694,7 @@ object Config {
interpreters.map { interp =>
Datacenter(
name = id,
docker = Infrastructure.Docker(kfg.require[String]("docker-registry")),
docker = readDocker(kfg),
domain = Infrastructure.Domain(kfg.require[String]("domain")),
defaultTrafficShift = trafficShift,
proxyCredentials = proxyCreds,
Expand Down
7 changes: 3 additions & 4 deletions core/src/main/scala/Datacenter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ object Infrastructure {
)

final case class Docker(
registry: docker.Docker.RegistryURI
registry: docker.Docker.RegistryURI,
credentials: Option[docker.Docker.Credentials]
)

/**
Expand All @@ -67,9 +68,7 @@ object Infrastructure {
final case class Nomad(
endpoint: Uri,
timeout: Duration,
dockerRepoUser: String,
dockerRepoPassword: String,
dockerRepoServerAddress: String,
docker: Docker,
mhzPerCPU: Int
)

Expand Down
2 changes: 0 additions & 2 deletions core/src/main/scala/Exceptions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,6 @@ final case class InvalidUnitNameChars(name: String)
final case class UnknownBlueprintReference(ref: String, revision: blueprint.Blueprint.Revision)
extends NelsonError(s"the blueprint '${ref}@${revision.toString}' does not exist in the database; be sure you have specified the correct name and revision")

final object NomadNotImplemented extends NelsonError(s"Nelson 0.11.x+ currently does not support Nomad. If you are interested in using Nelson with Nomad please file an issue on GitHub: https://github.com/getnelson/nelson/ or reach out to us on Gitter: https://gitter.im/getnelson/nelson")

final case class VersionedGitTagRequired(ref: Github.Reference)
extends NelsonError(s"Nelson can presently only release from tags whilst the supplied ref was '${ref}'")

Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/blueprint/DefaultBlueprints.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ object DefaultBlueprints {
val cronJob = templateFromClasspath("nelson/canopus_cron_job.mustache")
val job = templateFromClasspath("nelson/canopus_job.mustache")
}

val magnetar = templateFromClasspath("nelson/magnetar.mustache")
}
1 change: 0 additions & 1 deletion core/src/main/scala/blueprint/Render.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,4 @@ object Render {
val envvarName = "envvar_name"
val envvarValue = "envvar_value"
}

}
4 changes: 4 additions & 0 deletions core/src/main/scala/docker/Docker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ object Docker {
type Name = String
type Tag = String
type Digest = String
type User = String
type Password = String

final case class Image(
name: Name,
Expand Down Expand Up @@ -215,4 +217,6 @@ object Docker {
}
}
}

final case class Credentials(user: User, password: Password)
}
1 change: 1 addition & 0 deletions core/src/main/scala/scheduler/KubernetesShell.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ final class KubernetesShell(
error.stderr.exists(_.startsWith("Error from server (NotFound)"))

def launch(image: Image, dc: Datacenter, ns: NamespaceName, unit: UnitDef, version: Version, plan: Plan, hash: String): IO[String] = {
val sn = StackName(unit.name, version, hash)
val env = Render.makeEnv(image, dc, ns, unit, version, plan, hash)

val fallback = Manifest.getSchedule(unit, plan) match {
Expand Down
Loading