aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--docs/shoelaces.8.scd4
-rw-r--r--internal/handlers/polling.go10
-rw-r--r--internal/polling/polling.go30
-rw-r--r--internal/router/router.go3
-rw-r--r--web/templates/html/index.html2
6 files changed, 48 insertions, 5 deletions
diff --git a/README.md b/README.md
index 18d8e64..fec8e04 100644
--- a/README.md
+++ b/README.md
@@ -141,7 +141,7 @@ with your TFTP and Shoelaces server addresses.
# dhcp.conf
next-server <your-tftp-server>;
if exists user-class and option user-class = "iPXE" {
- filename "http://<shoelaces-server>/poll/1/${netX/mac:hexhyp}";
+ filename "http://<shoelaces-server>/start";
} else {
filename "undionly.kpxe";
}
@@ -153,7 +153,7 @@ putting it in `dnsmasq.d/ipxe.conf`:
```txt
dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
dhcp-boot=tag:!ipxe,undionly.kpxe
-dhcp-boot=http://<shoelaces-server>/poll/1/${netX/mac:hexhyp}
+dhcp-boot=http://<shoelaces-server>/start
```
The **${netX/mac:hexhyp}** strings represents the MAC address of the booting
diff --git a/docs/shoelaces.8.scd b/docs/shoelaces.8.scd
index 445994c..f803dd3 100644
--- a/docs/shoelaces.8.scd
+++ b/docs/shoelaces.8.scd
@@ -88,7 +88,7 @@ debug=true
# dhcp.conf
next-server <your-tftp-server>;
if exists user-class and option user-class = "iPXE" {
- filename "http://<shoelaces-server>/poll/1/${netX/mac:hexhyp}";
+ filename "http://<shoelaces-server>/start";
} else {
filename "undionly.kpxe";
}
@@ -100,7 +100,7 @@ the following snippet:
```
dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
dhcp-boot=tag:!ipxe,undionly.kpxe
-dhcp-boot=http://<shoelaces-server>/poll/1/${netX/mac:hexhyp}
+dhcp-boot=http://<shoelaces-server>/start
```
A TFTP server such as *tftpd*(8) must be configured to serve the iPXE executable,
diff --git a/internal/handlers/polling.go b/internal/handlers/polling.go
index 12f36e2..51fd8ad 100644
--- a/internal/handlers/polling.go
+++ b/internal/handlers/polling.go
@@ -28,6 +28,16 @@ import (
"github.com/thousandeyes/shoelaces/internal/utils"
)
+// StartPollingHandler is called by iPXE boot agents. It returns the poll script.
+func StartPollingHandler(w http.ResponseWriter, r *http.Request) {
+ env := envFromRequest(r)
+
+ script := polling.GenStartScript(env.Logger, env.BaseURL)
+
+ w.Write([]byte(script))
+}
+
+
// PollHandler is called by iPXE boot agents. It returns the boot script
// specified on the configuration or, if the host is unknown, it makes it
// retry for a while until the user specifies alternative IPXE boot script.
diff --git a/internal/polling/polling.go b/internal/polling/polling.go
index 853a751..cfd489f 100644
--- a/internal/polling/polling.go
+++ b/internal/polling/polling.go
@@ -34,6 +34,16 @@ import (
type ManualAction int
const (
+ startScript = "#!ipxe\n" +
+ "echo Shoelaces starts polling\n" +
+ "chain --autofree --replace \\\n" +
+ " http://{{.baseURL}}/poll/1/${netX/mac:hexhyp}\n" +
+ "#\n" +
+ "#\n" +
+ "# Do\n" +
+ "# curl http://{{.baseURL}}/poll/1/06-66-de-ad-be-ef\n" +
+ "# to get an idea about what iPXE will receive.\n"
+
maxRetry = 10
retryScript = "#!ipxe\n" +
@@ -226,6 +236,26 @@ func setHostName(params map[string]interface{}, mac string) {
}
}
+func GenStartScript(logger log.Logger, baseURL string) string {
+ variablesMap := map[string]interface{}{}
+ parsedTemplate := &bytes.Buffer{}
+
+ tmpl, err := template.New("retry").Parse(startScript)
+ if err != nil {
+ logger.Info("component", "polling", "msg", "Error parsing start template")
+ panic(err)
+ }
+
+ variablesMap["baseURL"] = baseURL
+ err = tmpl.Execute(parsedTemplate, variablesMap)
+ if err != nil {
+ logger.Info("component", "polling", "msg", "Error executing start template")
+ panic(err)
+ }
+
+ return parsedTemplate.String()
+}
+
func genBootScript(logger log.Logger, templateRenderer *templates.ShoelacesTemplates, baseURL string, script *mappings.Script) string {
script.Params["baseURL"] = utils.BaseURLforEnvName(baseURL, script.Environment)
text, err := templateRenderer.RenderTemplate(logger, script.Name, script.Params, script.Environment)
diff --git a/internal/router/router.go b/internal/router/router.go
index d729d16..1313705 100644
--- a/internal/router/router.go
+++ b/internal/router/router.go
@@ -53,6 +53,9 @@ func ShoelacesRouter(env *environment.Environment) http.Handler {
r.PathPrefix("/configs/").Handler(http.StripPrefix("/configs/",
handlers.TemplateServer()))
+ // Starting point for iPXE boot agents, usualy defined by DHCP server.
+ // Gets the iPXE boot agents into the polling loop.
+ r.HandleFunc("/start", handlers.StartPollingHandler).Methods("GET")
// Called by iPXE boot agents, returns boot script specified on the configuration
// or if the host is unknown makes it retry for a while until the user specifies
// alternative ipxe boot script
diff --git a/web/templates/html/index.html b/web/templates/html/index.html
index 4f09ba9..ea93c01 100644
--- a/web/templates/html/index.html
+++ b/web/templates/html/index.html
@@ -31,7 +31,7 @@
<div class="center-block col-md-6">
<div class="card">
<div class="card-body">
- <p class="text-center">Shoelaces is waiting for a server to boot. Using iPXE, your server should reach the following endpoint: <br /> <b class="text-primary-custom">http://{{ .BaseURL }}/poll/1/&#60;MAC&#62;</b> </p>
+ <p class="text-center">Shoelaces is waiting for a server to boot. Using iPXE, your server should reach the following endpoint: <br /> <b class="text-primary-custom">http://{{ .BaseURL }}/start</b> </p>
<p class="text-center">You can automate this process by setting up a DHCP server.</p>
</div>
</div>
nihil fit ex nihilo