lang: core: embedded: provisioner: Support exec handoff
Could be used for any tool, but mgmt is an obvious possibility. I should check this code more, but it's roughly right and I'm sure it will get refactored more when I build opt-in provisioning and so on.
This commit is contained in:
@@ -576,6 +576,7 @@ class base:host($name, $config) {
|
|||||||
$provision_default = $config->provision || false # false is safest!
|
$provision_default = $config->provision || false # false is safest!
|
||||||
|
|
||||||
$handoff_type = $config->handoff || ""
|
$handoff_type = $config->handoff || ""
|
||||||
|
$handoff_exec = $config->handoff_exec || ""
|
||||||
$handoff_code = $config->handoff_code || ""
|
$handoff_code = $config->handoff_code || ""
|
||||||
$handoff_module_path = $config->handoff_module_path || ""
|
$handoff_module_path = $config->handoff_module_path || ""
|
||||||
panic($handoff_code != "" and not golang_strings.has_prefix($handoff_code, "/"))
|
panic($handoff_code != "" and not golang_strings.has_prefix($handoff_code, "/"))
|
||||||
@@ -756,28 +757,35 @@ class base:host($name, $config) {
|
|||||||
panic($handoff_type != "" and len($handoff_packages) == 0)
|
panic($handoff_type != "" and len($handoff_packages) == 0)
|
||||||
#$handoff_packages_string = golang_strings.join($handoff_packages, " ")
|
#$handoff_packages_string = golang_strings.join($handoff_packages, " ")
|
||||||
|
|
||||||
|
$sshkey_flag = "sshkey"
|
||||||
|
$sshkey_type = "ed25519" # TODO: support other options
|
||||||
|
$sshkey_path = "/root/.ssh/id_${sshkey_type}"
|
||||||
|
$setup_sshkey = "mkdir -p '/root/.ssh/' -m 700 && ssh-keygen -N '' -t '${sshkey_type}' -f '${sshkey_path}'" # non-interactive
|
||||||
|
# Setting up the known_hosts file isn't needed since that can be done on
|
||||||
|
# the first run of mgmt, and the initial key can come in from --ssh-url.
|
||||||
|
|
||||||
$handoff_binary = if $handoff_type == "" {
|
$handoff_binary = if $handoff_type == "" {
|
||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
# Copy over the actual mgmt binary. This enables a lot below...
|
# Copy over the actual mgmt binary. This enables a lot below...
|
||||||
"/usr/bin/wget -O '${handoff_binary_path}' 'http://${router_ip}:${http_port_str}/mgmt/binary' && /usr/bin/chmod u+x '${handoff_binary_path}'"
|
"/usr/bin/wget -O '${handoff_binary_path}' 'http://${router_ip}:${http_port_str}/mgmt/binary' && /usr/bin/chmod u+x '${handoff_binary_path}'"
|
||||||
}
|
}
|
||||||
$handoff_cpcode = if $handoff_type == "" {
|
$handoff_cpcode = if $handoff_type == "code" {
|
||||||
""
|
|
||||||
} else {
|
|
||||||
# Download a tar ball of our code.
|
# Download a tar ball of our code.
|
||||||
# TODO: Alternate mechanisms of getting the code are possible.
|
# TODO: Alternate mechanisms of getting the code are possible.
|
||||||
if $handoff_code != "" {
|
if $mac != "" {
|
||||||
"/usr/bin/wget -O /root/mgmt-deploy.tar.gz 'http://${router_ip}:${http_port_str}/mgmt/deploy-${provision_key}.tar.gz' && /usr/bin/mkdir '${deploy_dir}' && /usr/bin/tar -xf /root/mgmt-deploy.tar.gz --directory '${deploy_dir}'"
|
"/usr/bin/wget -O /root/mgmt-deploy.tar.gz 'http://${router_ip}:${http_port_str}/mgmt/deploy-${provision_key}.tar.gz' && /usr/bin/mkdir '${deploy_dir}' && /usr/bin/tar -xf /root/mgmt-deploy.tar.gz --directory '${deploy_dir}'"
|
||||||
} else {
|
} else {
|
||||||
"/usr/bin/wget -O /root/mgmt-deploy.tar.gz 'http://${router_ip}:${http_port_str}/mgmt/deploy.tar.gz' && /usr/bin/mkdir '${deploy_dir}' && /usr/bin/tar -xf /root/mgmt-deploy.tar.gz --directory '${deploy_dir}'"
|
"/usr/bin/wget -O /root/mgmt-deploy.tar.gz 'http://${router_ip}:${http_port_str}/mgmt/deploy.tar.gz' && /usr/bin/mkdir '${deploy_dir}' && /usr/bin/tar -xf /root/mgmt-deploy.tar.gz --directory '${deploy_dir}'"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$handoff_service = if $handoff_type == "" {
|
|
||||||
""
|
|
||||||
} else {
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
$handoff_service = if $handoff_type == "code" { # TODO: maybe add it in other scenarios
|
||||||
# Setup the mgmt service, which starts on firstboot.
|
# Setup the mgmt service, which starts on firstboot.
|
||||||
"${handoff_binary_path} setup svc --binary-path='${handoff_binary_path}' --install --enable"
|
"${handoff_binary_path} setup svc --binary-path='${handoff_binary_path}' --install --enable"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
}
|
}
|
||||||
$handoff_firstboot = if $handoff_type == "" {
|
$handoff_firstboot = if $handoff_type == "" {
|
||||||
""
|
""
|
||||||
@@ -785,24 +793,28 @@ class base:host($name, $config) {
|
|||||||
# Setup the firstboot service itself.
|
# Setup the firstboot service itself.
|
||||||
"${handoff_binary_path} setup firstboot --binary-path='${handoff_binary_path}' --mkdir --install --enable --scripts-dir='${firstboot_scripts_dir}' --done-dir='${firstboot_done_dir}'"
|
"${handoff_binary_path} setup firstboot --binary-path='${handoff_binary_path}' --mkdir --install --enable --scripts-dir='${firstboot_scripts_dir}' --done-dir='${firstboot_done_dir}'"
|
||||||
}
|
}
|
||||||
$handoff_deploy = if $handoff_type == "" {
|
|
||||||
""
|
$handoff_firstboot_exec = if $handoff_type == "exec" and $handoff_exec != "" {
|
||||||
|
# Add a script that will run by our firstboot service on boot.
|
||||||
|
# This usually just runs mgmt over the network to etcd.
|
||||||
|
"echo '#!/usr/bin/env bash' > ${firstboot_scripts_dir}mgmt-exec.sh && echo 'ulimit -n 16384' >> ${firstboot_scripts_dir}mgmt-exec.sh && echo '${handoff_exec}' >> ${firstboot_scripts_dir}mgmt-exec.sh && chmod u+x ${firstboot_scripts_dir}mgmt-exec.sh"
|
||||||
} else {
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
$handoff_firstboot_code = if $handoff_type == "code" {
|
||||||
# Add a script that will run by our firstboot service on boot.
|
# Add a script that will run by our firstboot service on boot.
|
||||||
# It seems that the deploy will hang until mgmt is started...
|
# It seems that the deploy will hang until mgmt is started...
|
||||||
# NOTE: We need to add the $handoff_code arg the same way it was
|
# NOTE: We need to add the $handoff_code arg the same way it was
|
||||||
# passed into the provisioner. It's just now in a deploy subdir.
|
# passed into the provisioner. It's just now in a deploy subdir.
|
||||||
# If it's a dir, then this becomes the empty strings.
|
# If it's a dir, then this becomes the empty strings.
|
||||||
# XXX: The deploy could instead happen over the network to etcd.
|
"echo '#!/usr/bin/env bash' > ${firstboot_scripts_dir}mgmt-code.sh && echo '${handoff_binary_path} deploy lang --seeds=http://127.0.0.1:2379 --no-git --module-path=${deploy_dir_modules} ${deploy_dir}${handoff_code_chunk}' >> ${firstboot_scripts_dir}mgmt-code.sh && chmod u+x ${firstboot_scripts_dir}mgmt-code.sh"
|
||||||
"echo '#!/usr/bin/env bash' > ${firstboot_scripts_dir}mgmt-deploy.sh && echo '${handoff_binary_path} deploy lang --seeds=http://127.0.0.1:2379 --no-git --module-path=${deploy_dir_modules} ${deploy_dir}${handoff_code_chunk}' >> ${firstboot_scripts_dir}mgmt-deploy.sh && chmod u+x ${firstboot_scripts_dir}mgmt-deploy.sh"
|
} else {
|
||||||
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: Do we want to signal an http:server:flag if we're a "default" host?
|
# TODO: Do we want to signal an http:server:flag if we're a "default" host?
|
||||||
$provisioning_done = if $provision_key == "default" {
|
$provisioning_done = "/usr/bin/curl --data-urlencode 'done=true' --data-urlencode 'password=sha1TODO' --data-urlencode 'sshtype=ssh-${sshkey_type}' --data-urlencode \"${sshkey_flag}=\$(cut -d ' ' -f 2 '${sshkey_path}.pub')\" --data-urlencode 'sshcomment=root@${handoff_hostname}' -o - 'http://${router_ip}:${http_port_str}/action/done/mac=${provision_key}'"
|
||||||
""
|
|
||||||
} else {
|
|
||||||
"/usr/bin/wget --post-data 'done=true&password=sha1TODO' -O - 'http://${router_ip}:${http_port_str}/action/done/mac=${provision_key}'"
|
|
||||||
}
|
|
||||||
|
|
||||||
$http_kickstart_template = struct{
|
$http_kickstart_template = struct{
|
||||||
comment => "hello!",
|
comment => "hello!",
|
||||||
@@ -836,11 +848,13 @@ class base:host($name, $config) {
|
|||||||
#],
|
#],
|
||||||
hostname => $handoff_hostname,
|
hostname => $handoff_hostname,
|
||||||
post => [
|
post => [
|
||||||
|
$setup_sshkey, # setup the ssh key
|
||||||
$handoff_binary, # copy over the binary
|
$handoff_binary, # copy over the binary
|
||||||
$handoff_cpcode, # copy over a bundle of code
|
$handoff_cpcode, # copy over a bundle of code
|
||||||
$handoff_service, # install a service for mgmt
|
$handoff_service, # install a service for mgmt
|
||||||
$handoff_firstboot, # install firstboot service
|
$handoff_firstboot, # install firstboot service
|
||||||
$handoff_deploy, # install a firstboot script to deploy
|
$handoff_firstboot_exec, # install a firstboot script to exec
|
||||||
|
$handoff_firstboot_code, # install a firstboot script to deploy
|
||||||
$provisioning_done, # send a done signal back here
|
$provisioning_done, # send a done signal back here
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -871,20 +885,40 @@ class base:host($name, $config) {
|
|||||||
|
|
||||||
##$str_true = convert.format_bool(true)
|
##$str_true = convert.format_bool(true)
|
||||||
##$str_false = convert.format_bool(false)
|
##$str_false = convert.format_bool(false)
|
||||||
#http:server:flag "${name}" {
|
http:server:flag "${name}-done" {
|
||||||
# key => "done",
|
key => "done",
|
||||||
# path => "/action/done/mac=${provision_key}",
|
path => "/action/done/mac=${provision_key}",
|
||||||
# #mapped => {$str_true => $str_true, $str_false => $str_false,},
|
#mapped => {$str_true => $str_true, $str_false => $str_false,},
|
||||||
#}
|
}
|
||||||
#kv "${name}" {
|
http:server:flag "${name}-sshkey" {
|
||||||
# key => $provision_key,
|
key => "${sshkey_flag}",
|
||||||
#}
|
path => "/action/done/mac=${provision_key}",
|
||||||
#value "${provision_key}" {
|
}
|
||||||
# #any => true, # bool
|
|
||||||
#}
|
# TODO: rename the names of kv and value here?
|
||||||
#Http:Flag["${name}"].value -> Kv["${name}"].value
|
kv "${name}-done" {
|
||||||
#Http:Flag["${name}"].value -> Value["${provision_key}"].any
|
key => $provision_key,
|
||||||
##$st_provisioned = value.get_bool($provision_key)
|
}
|
||||||
|
value "${name}-done" {
|
||||||
|
#any => true, # bool
|
||||||
|
}
|
||||||
|
kv "${name}-sshkey" {
|
||||||
|
key => $provision_key,
|
||||||
|
}
|
||||||
|
value "${name}-sshkey" {
|
||||||
|
#any => "",
|
||||||
|
}
|
||||||
|
|
||||||
|
Http:Server:Flag["${name}-done"].value -> Kv["${name}-done"].value
|
||||||
|
Http:Server:Flag["${name}-done"].value -> Value["${name}-done"].any
|
||||||
|
Http:Server:Flag["${name}-sshkey"].value -> Kv["${name}-sshkey"].value
|
||||||
|
Http:Server:Flag["${name}-sshkey"].value -> Value["${name}-sshkey"].any
|
||||||
|
|
||||||
|
#$st_provisioned = value.get_bool($provision_key)
|
||||||
#$st_provisioned = value.get_str($provision_key)
|
#$st_provisioned = value.get_str($provision_key)
|
||||||
#$provisioned = $st_provisioned->ready and $st_provisioned->value == "true" # export this value to parent scope
|
$st_done = value.get_str("${name}-done")
|
||||||
|
$provisioned = $st_done->ready and $st_done->value == "true" # export this value to parent scope
|
||||||
|
|
||||||
|
$st_sshkey = value.get_str("${name}-sshkey")
|
||||||
|
$sshkey = $st_sshkey->value # export this value to parent scope
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,6 +167,10 @@ type localArgs struct {
|
|||||||
// other or the base installation packages.
|
// other or the base installation packages.
|
||||||
Packages []string `arg:"--packages,separate" help:"list of additional distro packages to install" func:"cli_packages"`
|
Packages []string `arg:"--packages,separate" help:"list of additional distro packages to install" func:"cli_packages"`
|
||||||
|
|
||||||
|
// HandoffExec specifies that we want to handoff to this machine by
|
||||||
|
// running a single exec on firstboot. Usually an `mgmt run` command.
|
||||||
|
HandoffExec string `arg:"--handoff-exec" help:"exec command to run on firstboot" func:"cli_handoff_exec"` // eg: mgmt run ...
|
||||||
|
|
||||||
// HandoffCode specifies that we want to handoff to this machine with a
|
// HandoffCode specifies that we want to handoff to this machine with a
|
||||||
// static code deploy bolus. This is useful for isolated, one-time runs.
|
// static code deploy bolus. This is useful for isolated, one-time runs.
|
||||||
HandoffCode string `arg:"--handoff-code" help:"code dir to handoff to host" func:"cli_handoff_code"` // eg: /etc/mgmt/
|
HandoffCode string `arg:"--handoff-code" help:"code dir to handoff to host" func:"cli_handoff_code"` // eg: /etc/mgmt/
|
||||||
|
|||||||
@@ -59,10 +59,14 @@ $distro = provisioner.cli_distro()
|
|||||||
$version = provisioner.cli_version()
|
$version = provisioner.cli_version()
|
||||||
$arch = provisioner.cli_arch()
|
$arch = provisioner.cli_arch()
|
||||||
$uid = "${distro}${version}-${arch}" # eg: fedora39-x86_64
|
$uid = "${distro}${version}-${arch}" # eg: fedora39-x86_64
|
||||||
$handoff = if provisioner.cli_handoff_code() == "" { # TODO: check other types
|
$handoff = if provisioner.cli_handoff_code() != "" { # TODO: check other types
|
||||||
""
|
"code"
|
||||||
} else {
|
} else {
|
||||||
"code" # some non-empty word
|
if provisioner.cli_handoff_exec() != "" { # TODO: check other types
|
||||||
|
"exec"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
include base.host("host0", struct{ # TODO: do we need a usable name anywhere?
|
include base.host("host0", struct{ # TODO: do we need a usable name anywhere?
|
||||||
#repo => $repo.uid, # type unification performance is very slow here
|
#repo => $repo.uid, # type unification performance is very slow here
|
||||||
@@ -76,6 +80,7 @@ include base.host("host0", struct{ # TODO: do we need a usable name anywhere?
|
|||||||
packages => provisioner.cli_packages(),
|
packages => provisioner.cli_packages(),
|
||||||
#provision => true, # default if unspecified
|
#provision => true, # default if unspecified
|
||||||
handoff => $handoff, # alternatively some code word or querystring
|
handoff => $handoff, # alternatively some code word or querystring
|
||||||
|
handoff_exec => provisioner.cli_handoff_exec(),
|
||||||
#handoff_code => "/etc/mgmt/", # one way to do it
|
#handoff_code => "/etc/mgmt/", # one way to do it
|
||||||
handoff_code => provisioner.cli_handoff_code(),
|
handoff_code => provisioner.cli_handoff_code(),
|
||||||
handoff_module_path => provisioner.cli_handoff_module_path(),
|
handoff_module_path => provisioner.cli_handoff_module_path(),
|
||||||
@@ -85,6 +90,6 @@ include base.host("host0", struct{ # TODO: do we need a usable name anywhere?
|
|||||||
|
|
||||||
#if $host0.provisioned {
|
#if $host0.provisioned {
|
||||||
# print "provisioned" {
|
# print "provisioned" {
|
||||||
# msg => fmt.printf("%s is provisioned!", $host0.name),
|
# msg => fmt.printf("%s has ssh key: %s", $host0.name, $host0.sshkey),
|
||||||
# }
|
# }
|
||||||
#}
|
#}
|
||||||
|
|||||||
Reference in New Issue
Block a user