Files
zeekay b61441f7d7 Volume: node-local persistent volumes, under our own name
A fork of Rancher's local-path-provisioner at v0.0.36. The behaviour is
unchanged and deliberately so — a directory on the node a pod lands on is
the right thing for a disk. What changes is identity.

The provisioner answers to hanzo.ai/volume rather than rancher.io/local-path.
That is not branding: two provisioners sharing one name race for the same
claims, and a stock k3s carries the upstream one, so a cluster running both
would settle our storage by chance. Data lives at /var/lib/hanzo/volume, so
reading a Hanzo cluster does not mean learning another vendor's directory.

Apache-2.0 as published, unaltered, with Rancher's attribution in NOTICE.

The README says what this is not: durability. A volume here dies with its
node. That is hanzoai/replicate's question, one layer up, and keeping the
two apart is what lets the disk stay this simple.
2026-09-07 17:30:01 -07:00

75 lines
2.1 KiB
Go

package restful
import (
"bytes"
"strings"
)
// Copyright 2018 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.
// PathProcessor is extra behaviour that a Router can provide to extract path parameters from the path.
// If a Router does not implement this interface then the default behaviour will be used.
type PathProcessor interface {
// ExtractParameters gets the path parameters defined in the route and webService from the urlPath
ExtractParameters(route *Route, webService *WebService, urlPath string) map[string]string
}
type defaultPathProcessor struct{}
// Extract the parameters from the request url path
func (d defaultPathProcessor) ExtractParameters(r *Route, _ *WebService, urlPath string) map[string]string {
urlParts := tokenizePath(urlPath)
pathParameters := map[string]string{}
for i, key := range r.pathParts {
var value string
if i >= len(urlParts) {
value = ""
} else {
value = urlParts[i]
}
if r.hasCustomVerb && hasCustomVerb(key) {
key = removeCustomVerb(key)
value = removeCustomVerb(value)
}
if strings.Index(key, "{") > -1 { // path-parameter
if colon := strings.Index(key, ":"); colon != -1 {
// extract by regex
regPart := key[colon+1 : len(key)-1]
keyPart := key[1:colon]
if regPart == "*" {
pathParameters[keyPart] = untokenizePath(i, urlParts)
break
} else {
pathParameters[keyPart] = value
}
} else {
// without enclosing {}
startIndex := strings.Index(key, "{")
endKeyIndex := strings.Index(key, "}")
suffixLength := len(key) - endKeyIndex - 1
endValueIndex := len(value) - suffixLength
pathParameters[key[startIndex+1:endKeyIndex]] = value[startIndex:endValueIndex]
}
}
}
return pathParameters
}
// Untokenize back into an URL path using the slash separator
func untokenizePath(offset int, parts []string) string {
var buffer bytes.Buffer
for p := offset; p < len(parts); p++ {
buffer.WriteString(parts[p])
// do not end
if p < len(parts)-1 {
buffer.WriteString("/")
}
}
return buffer.String()
}