refactor: use strings.CutPrefix/CutSuffix for guard-then-trim pairs

This commit is contained in:
Julian Sommer
2026-09-16 16:18:33 +10:00
parent 4b35de1409
commit 0c83f7f954
27 changed files with 108 additions and 89 deletions
+5 -4
View File
@@ -94,7 +94,8 @@ func rekeyRecordSeparator(ctx context.Context, kvc migrate.KVContext) error {
moved := 0
for _, key := range keys {
if !strings.HasPrefix(key, slashRecordPrefix) {
instanceID, ok := strings.CutPrefix(key, slashRecordPrefix)
if !ok {
continue
}
@@ -106,7 +107,7 @@ func rekeyRecordSeparator(ctx context.Context, kvc migrate.KVContext) error {
return fmt.Errorf("read %s: %w", key, err)
}
dest := instanceRecordKey(strings.TrimPrefix(key, slashRecordPrefix))
dest := instanceRecordKey(instanceID)
if _, err := kvc.KV.Create(ctx, dest, entry.Value()); err != nil {
if !errors.Is(err, jetstream.ErrKeyExists) {
return fmt.Errorf("write %s: %w", dest, err)
@@ -151,10 +152,10 @@ func carryNodeOwnershipForward(ctx context.Context, kvc migrate.KVContext) error
seeded, owned := 0, 0
for _, key := range keys {
if !strings.HasPrefix(key, InstanceStatePrefix) {
nodeID, ok := strings.CutPrefix(key, InstanceStatePrefix)
if !ok {
continue
}
nodeID := strings.TrimPrefix(key, InstanceStatePrefix)
if _, err := kvc.KV.Create(ctx, NodePresencePrefix+nodeID, marker); err != nil {
// A node that has already upgraded wrote its own marker; it is the
+2 -2
View File
@@ -58,10 +58,10 @@ func MatchesAny(filterValues []string, value string) bool {
// Each tag:Key filter uses OR logic across its values, with wildcard support.
func MatchesTags(filters map[string][]string, tags map[string]string) bool {
for name, values := range filters {
if !strings.HasPrefix(name, "tag:") {
tagKey, ok := strings.CutPrefix(name, "tag:")
if !ok {
continue
}
tagKey := name[4:] // strip "tag:" prefix
tagValue, exists := tags[tagKey]
if !exists {
return false
+21 -14
View File
@@ -192,11 +192,12 @@ func setAnthropicCompletionTexts(body []byte, texts []string) ([]byte, error) {
// extractTokenUsage's own backend switch. ok is false when body doesn't
// decode as backend's shape or backend has no guardrail support.
func extractInvokePromptTexts(backend string, body []byte) (texts []string, ok bool) {
vendor, isVendor := strings.CutPrefix(backend, providerPrefix)
switch {
case backend == tierSelfHost:
return extractLlamaPromptTexts(body)
case strings.HasPrefix(backend, providerPrefix):
switch strings.TrimPrefix(backend, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
return extractAnthropicPromptTexts(body)
}
@@ -206,11 +207,12 @@ func extractInvokePromptTexts(backend string, body []byte) (texts []string, ok b
// extractInvokeCompletionTexts is extractInvokePromptTexts' OUTPUT sibling.
func extractInvokeCompletionTexts(backend string, body []byte) (texts []string, ok bool) {
vendor, isVendor := strings.CutPrefix(backend, providerPrefix)
switch {
case backend == tierSelfHost:
return extractLlamaCompletionTexts(body)
case strings.HasPrefix(backend, providerPrefix):
switch strings.TrimPrefix(backend, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
return extractAnthropicCompletionTexts(body)
}
@@ -222,11 +224,12 @@ func extractInvokeCompletionTexts(backend string, body []byte) (texts []string,
// InvokeModel response body carrying message as the assistant text, for an
// INPUT guardrail block -- the backend is never called.
func invokeGuardrailBlockedResponse(backend, modelID, message string) ([]byte, error) {
vendor, isVendor := strings.CutPrefix(backend, providerPrefix)
switch {
case backend == tierSelfHost:
return buildLlamaBlockedResponse(message)
case strings.HasPrefix(backend, providerPrefix):
switch strings.TrimPrefix(backend, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
return buildAnthropicBlockedResponse(modelID, message)
}
@@ -237,11 +240,12 @@ func invokeGuardrailBlockedResponse(backend, modelID, message string) ([]byte, e
// invokeGuardrailBlockedCompletion rewrites respBody's assistant text
// wholesale with message, for an OUTPUT guardrail block.
func invokeGuardrailBlockedCompletion(backend string, respBody []byte, message string) ([]byte, error) {
vendor, isVendor := strings.CutPrefix(backend, providerPrefix)
switch {
case backend == tierSelfHost:
return replaceLlamaCompletion(respBody, message)
case strings.HasPrefix(backend, providerPrefix):
switch strings.TrimPrefix(backend, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
return replaceAnthropicCompletion(respBody, message)
}
@@ -252,14 +256,15 @@ func invokeGuardrailBlockedCompletion(backend string, respBody []byte, message s
// invokeGuardrailRedactedCompletion rewrites respBody's assistant text
// positionally with texts, for an OUTPUT ANONYMIZE redaction.
func invokeGuardrailRedactedCompletion(backend string, respBody []byte, texts []string) ([]byte, error) {
vendor, isVendor := strings.CutPrefix(backend, providerPrefix)
switch {
case backend == tierSelfHost:
if len(texts) == 0 {
return respBody, nil
}
return setLlamaCompletionText(respBody, texts[0])
case strings.HasPrefix(backend, providerPrefix):
switch strings.TrimPrefix(backend, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
return setAnthropicCompletionTexts(respBody, texts)
}
@@ -271,6 +276,7 @@ func invokeGuardrailRedactedCompletion(backend string, respBody []byte, texts []
// invoke-stream chunk for buffered OUTPUT accumulation. ok=false is a benign
// no-text chunk; decodeErr=true is a real JSON-decode failure (fail closed).
func extractInvokeStreamChunkText(backend string, chunk []byte) (text string, ok bool, decodeErr bool) {
vendor, isVendor := strings.CutPrefix(backend, providerPrefix)
switch {
case backend == tierSelfHost:
var c struct {
@@ -280,8 +286,8 @@ func extractInvokeStreamChunkText(backend string, chunk []byte) (text string, ok
return "", false, true
}
return c.Generation, c.Generation != "", false
case strings.HasPrefix(backend, providerPrefix):
switch strings.TrimPrefix(backend, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
var c struct {
Type string `json:"type"`
@@ -361,11 +367,12 @@ func anthropicGuardedStreamChunks(message string, blocked bool) ([][]byte, error
// buildGuardedInvokeStreamChunks dispatches to the family-specific guarded
// invoke-stream chunk builder for backend.
func buildGuardedInvokeStreamChunks(backend, message string, blocked bool) ([][]byte, error) {
vendor, isVendor := strings.CutPrefix(backend, providerPrefix)
switch {
case backend == tierSelfHost:
return llamaGuardedStreamChunks(message, blocked)
case strings.HasPrefix(backend, providerPrefix):
switch strings.TrimPrefix(backend, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
return anthropicGuardedStreamChunks(message, blocked)
}
+6 -4
View File
@@ -135,6 +135,7 @@ func (rt *InvokeRouter) InvokeModel(ctx context.Context, accountID, modelID stri
backend = entry.Provider
var a InvokeAdapter
vendor, isVendor := strings.CutPrefix(entry.Provider, providerPrefix)
switch {
case entry.Provider == tierSelfHost:
// Family validation first: a model this platform cannot serve at
@@ -150,8 +151,8 @@ func (rt *InvokeRouter) InvokeModel(ctx context.Context, accountID, modelID stri
return nil, "", err
}
defer release()
case strings.HasPrefix(entry.Provider, providerPrefix):
switch strings.TrimPrefix(entry.Provider, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
var key string
var resolvable bool
@@ -323,6 +324,7 @@ func (rt *InvokeStreamRouter) InvokeModelWithResponseStream(ctx context.Context,
// once, either explicitly here or via the slot-releasing source wrapper
// on the success path.
var selfHostRelease func()
vendor, isVendor := strings.CutPrefix(entry.Provider, providerPrefix)
switch {
case entry.Provider == tierSelfHost:
// Family validation first: a model this platform cannot serve at
@@ -336,8 +338,8 @@ func (rt *InvokeStreamRouter) InvokeModelWithResponseStream(ctx context.Context,
if err != nil {
return nil, err
}
case strings.HasPrefix(entry.Provider, providerPrefix):
switch strings.TrimPrefix(entry.Provider, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
key, ok, err := rt.resolver.Resolve(ctx, accountID, vendorAnthropic)
if err != nil {
+6 -4
View File
@@ -133,6 +133,7 @@ func (rt *Router) Converse(ctx context.Context, accountID, modelID string, input
backend = entry.Provider
var p Provider
vendor, isVendor := strings.CutPrefix(entry.Provider, providerPrefix)
switch {
case entry.Provider == tierSelfHost:
var release func()
@@ -146,8 +147,8 @@ func (rt *Router) Converse(ctx context.Context, accountID, modelID string, input
} else {
p = newVLLMProvider(rt.endpointResolver)
}
case strings.HasPrefix(entry.Provider, providerPrefix):
switch strings.TrimPrefix(entry.Provider, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
var key string
var resolvable bool
@@ -267,6 +268,7 @@ func (rt *Router) ConverseStream(ctx context.Context, accountID, modelID string,
// whether the eventual source gets slot-release wrapping and whether an
// error return past this point must release the slot explicitly.
var selfHostRelease func()
vendor, isVendor := strings.CutPrefix(entry.Provider, providerPrefix)
switch {
case entry.Provider == tierSelfHost:
selfHostRelease, err = admitSelfHost(ctx, rt.provisioned, ptAccountID, modelID, entry)
@@ -278,8 +280,8 @@ func (rt *Router) ConverseStream(ctx context.Context, accountID, modelID string,
} else {
p = newVLLMProvider(rt.endpointResolver)
}
case strings.HasPrefix(entry.Provider, providerPrefix):
switch strings.TrimPrefix(entry.Provider, providerPrefix) {
case isVendor:
switch vendor {
case vendorAnthropic:
key, ok, err := rt.resolver.Resolve(ctx, accountID, vendorAnthropic)
if err != nil {
+7 -7
View File
@@ -49,15 +49,15 @@ func (s *sseScanner) Next() (sseEvent, bool, error) {
}
continue // keepalive blank line between records
}
switch {
case strings.HasPrefix(line, ":"):
// comment/keepalive, ignore — does not start a record
case strings.HasPrefix(line, "event:"):
if strings.HasPrefix(line, ":") {
continue // comment/keepalive, does not start a record
}
if v, ok := strings.CutPrefix(line, "event:"); ok {
sawAny = true
event = strings.TrimSpace(strings.TrimPrefix(line, "event:"))
case strings.HasPrefix(line, "data:"):
event = strings.TrimSpace(v)
} else if v, ok := strings.CutPrefix(line, "data:"); ok {
sawAny = true
dataLines = append(dataLines, strings.TrimPrefix(strings.TrimPrefix(line, "data:"), " "))
dataLines = append(dataLines, strings.TrimPrefix(v, " "))
}
}
+3 -2
View File
@@ -114,6 +114,7 @@ func classifyTagsOperation(method, name, ref string) (ClassifiedOperation, bool)
// classifyBlobOperation mirrors Registry.routeBlobs' dispatch exactly, so
// every method/ref combination it accepts has a matching authorization case.
func classifyBlobOperation(method, name, ref string, query url.Values) (ClassifiedOperation, bool) {
uploadID, isUpload := strings.CutPrefix(ref, "uploads/")
switch {
case ref == "uploads/" || ref == "uploads":
if method != http.MethodPost {
@@ -134,8 +135,8 @@ func classifyBlobOperation(method, name, ref string, query url.Values) (Classifi
op.Requirements = append(op.Requirements, ActionRequirement{ActionBatchCheckLayerAvailability, ScopeSource})
}
return op, true
case strings.HasPrefix(ref, "uploads/"):
if strings.TrimPrefix(ref, "uploads/") == "" {
case isUpload:
if uploadID == "" {
return ClassifiedOperation{}, false
}
switch method {
+2 -2
View File
@@ -164,14 +164,14 @@ func splitV2Path(path string) (name, kind, ref string, ok bool) {
func (reg *Registry) routeBlobs(w http.ResponseWriter, r *http.Request, name, ref string) {
ctx := r.Context()
uploadID, isUpload := strings.CutPrefix(ref, "uploads/")
switch {
case ref == "uploads/" || ref == "uploads":
if r.Method == http.MethodPost {
reg.startUpload(w, r, name)
return
}
case strings.HasPrefix(ref, "uploads/"):
uploadID := strings.TrimPrefix(ref, "uploads/")
case isUpload:
switch r.Method {
case http.MethodPatch:
reg.patchUpload(w, r, name, uploadID)
+1 -2
View File
@@ -50,8 +50,7 @@ func groupMembers(sysfsRoot string, groupNum int) ([]IOMMUGroupMember, error) {
// bind/unbind lifecycle while the endpoint is claimed.
func isBridgeClass(class string) bool {
s := strings.ToLower(strings.TrimSpace(class))
s = strings.TrimPrefix(s, "0x")
return len(s) >= 2 && s[:2] == "06"
return strings.HasPrefix(strings.TrimPrefix(s, "0x"), "06")
}
// filterBridgeMembers returns members with bridge-class devices removed.
+1 -4
View File
@@ -434,8 +434,5 @@ func (sc *Scheduler) convergeInstanceRoles(ctx context.Context) error {
// accountIDFromBucket extracts the account ID from an ECS per-account bucket name.
func accountIDFromBucket(bucket string) (string, bool) {
if !strings.HasPrefix(bucket, KVBucketECSAccountPrefix) {
return "", false
}
return strings.TrimPrefix(bucket, KVBucketECSAccountPrefix), true
return strings.CutPrefix(bucket, KVBucketECSAccountPrefix)
}
+3 -2
View File
@@ -97,11 +97,12 @@ func ListAddonRecords(ctx context.Context, kv jetstream.KeyValue, cluster string
prefix := AddonsPrefix(cluster)
out := make([]*AddonRecord, 0)
for _, k := range keys {
if !strings.HasPrefix(k, prefix) {
rest, ok := strings.CutPrefix(k, prefix)
if !ok {
continue
}
// Skip sub-keys (e.g. staged manifest); record keys are one segment under the prefix.
if strings.Contains(strings.TrimPrefix(k, prefix), "/") {
if strings.Contains(rest, "/") {
continue
}
entry, err := kv.Get(ctx, k)
+2 -2
View File
@@ -53,10 +53,10 @@ func ec2TagsFromMap(m map[string]string) []*ec2.Tag {
func cpvpcMatchTagFilters(tagMap map[string]string, filters []*ec2.Filter) bool {
for _, f := range filters {
name := aws.StringValue(f.Name)
if !strings.HasPrefix(name, "tag:") {
key, isTag := strings.CutPrefix(name, "tag:")
if !isTag {
continue
}
key := strings.TrimPrefix(name, "tag:")
got, ok := tagMap[key]
if !ok {
return false
+3 -2
View File
@@ -63,10 +63,11 @@ type etcdSnapshotKey struct {
// vary in length, so comparing the whole basename would not be.
func parseEtcdSnapshotKey(basename string) (etcdSnapshotKey, bool) {
const prefix, suffix = "etcd-", ".snap"
if !strings.HasPrefix(basename, prefix) || !strings.HasSuffix(basename, suffix) {
rest, prefixed := strings.CutPrefix(basename, prefix)
mid, suffixed := strings.CutSuffix(rest, suffix)
if !prefixed || !suffixed {
return etcdSnapshotKey{}, false
}
mid := strings.TrimSuffix(strings.TrimPrefix(basename, prefix), suffix)
i := strings.LastIndex(mid, "-")
if i <= 0 || i == len(mid)-1 {
return etcdSnapshotKey{}, false
+3 -2
View File
@@ -2503,10 +2503,11 @@ func listClusterNames(ctx context.Context, kv jetstream.KeyValue) ([]string, err
names := make([]string, 0, len(keys))
seen := make(map[string]struct{}, len(keys))
for _, k := range keys {
if !strings.HasPrefix(k, "clusters/") || !strings.HasSuffix(k, suffix) {
rest, prefixed := strings.CutPrefix(k, "clusters/")
name, suffixed := strings.CutSuffix(rest, suffix)
if !prefixed || !suffixed {
continue
}
name := strings.TrimSuffix(strings.TrimPrefix(k, "clusters/"), suffix)
if name == "" || strings.Contains(name, "/") {
continue
}
+2 -3
View File
@@ -42,11 +42,10 @@ type TokenVerifyResponse struct {
// `k8s-aws-v1.<base64url>` bearer token. The encoding is base64url without
// padding, matching the aws-iam-authenticator / aws-cli get-token output.
func DecodeGetToken(token string) (string, error) {
token = strings.TrimSpace(token)
if !strings.HasPrefix(token, getTokenV1Prefix) {
encoded, ok := strings.CutPrefix(strings.TrimSpace(token), getTokenV1Prefix)
if !ok {
return "", ErrMalformedToken
}
encoded := strings.TrimPrefix(token, getTokenV1Prefix)
raw, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
return "", ErrMalformedToken
+2 -2
View File
@@ -81,8 +81,8 @@ func imdsAction(method, path string) string {
return "imds.public-keys"
}
if strings.HasPrefix(path, prefixSecurityCreds) {
if len(path) > len(prefixSecurityCreds) {
if role, ok := strings.CutPrefix(path, prefixSecurityCreds); ok {
if role != "" {
return "imds.iam.security-credentials.role"
}
return "imds.iam.security-credentials.list"
+2 -2
View File
@@ -157,8 +157,8 @@ func (s *IMDSServiceImpl) dispatch(w http.ResponseWriter, r *http.Request, eni *
slog.InfoContext(ctx, "IMDS: serving metadata request", "path", path,
"instance_id", eni.instanceID, "private_ip", eni.privateIP, "public_ip", eni.publicIP)
if strings.HasPrefix(path, prefixSecurityCreds) && len(path) > len(prefixSecurityCreds) {
s.serveRoleCredentials(ctx, w, eni, strings.TrimPrefix(path, prefixSecurityCreds))
if role, ok := strings.CutPrefix(path, prefixSecurityCreds); ok && role != "" {
s.serveRoleCredentials(ctx, w, eni, role)
return
}
+3 -2
View File
@@ -132,7 +132,8 @@ func (r *metadataResolver) findENIByID(ctx context.Context, eniID string) (strin
suffix := "." + eniID
for _, key := range keys {
if !strings.HasSuffix(key, suffix) {
accountID, ok := strings.CutSuffix(key, suffix)
if !ok {
continue
}
entry, err := r.eniKV.Get(ctx, key)
@@ -142,7 +143,7 @@ func (r *metadataResolver) findENIByID(ctx context.Context, eniID string) (strin
}
return "", nil, fmt.Errorf("get eni record %s: %w", key, err)
}
return strings.TrimSuffix(key, suffix), entry.Value(), nil
return accountID, entry.Value(), nil
}
return "", nil, nil
}
@@ -168,13 +168,14 @@ func (f *fakeVPC) DescribeNetworkInterfaces(_ context.Context, in *ec2.DescribeN
for _, filter := range in.Filters {
name := aws.StringValue(filter.Name)
var got string
tagKey, isTag := strings.CutPrefix(name, "tag:")
switch {
case name == "subnet-id":
got = aws.StringValue(ni.SubnetId)
case name == "description":
got = aws.StringValue(ni.Description)
case strings.HasPrefix(name, "tag:"):
got = tagValue(ni.TagSet, strings.TrimPrefix(name, "tag:"))
case isTag:
got = tagValue(ni.TagSet, tagKey)
default:
return nil, fmt.Errorf("fakeVPC: unsupported ENI filter %q", name)
}
+5 -4
View File
@@ -306,10 +306,11 @@ func ListDBParameterGroupNames(ctx context.Context, kv jetstream.KeyValue) ([]st
prefix := DBParameterGroupsPrefix()
names := make([]string, 0, len(keys))
for _, key := range keys {
if !strings.HasPrefix(key, prefix) || !strings.HasSuffix(key, "/meta") {
rest, prefixed := strings.CutPrefix(key, prefix)
name, suffixed := strings.CutSuffix(rest, "/meta")
if !prefixed || !suffixed {
continue
}
name := strings.TrimSuffix(strings.TrimPrefix(key, prefix), "/meta")
if name == "" || strings.Contains(name, "/") {
continue
}
@@ -388,10 +389,10 @@ func listNames(ctx context.Context, kv jetstream.KeyValue, prefix string) ([]str
}
names := make([]string, 0, len(keys))
for _, key := range keys {
if !strings.HasPrefix(key, prefix) {
name, ok := strings.CutPrefix(key, prefix)
if !ok {
continue
}
name := strings.TrimPrefix(key, prefix)
if name == "" || strings.Contains(name, "/") {
continue
}
+8 -4
View File
@@ -226,19 +226,23 @@ type MIGProfileSpec struct {
MemoryMiB int64
}
// migTypePrefix marks an instance type name as a MIG profile type.
const migTypePrefix = "mig."
// IsMIGType reports whether the instance type name is a MIG profile type
// (i.e. was produced by GenerateMIGTypes).
func IsMIGType(instanceType string) bool {
return strings.HasPrefix(instanceType, "mig.")
return strings.HasPrefix(instanceType, migTypePrefix)
}
// MIGProfileFromType extracts the nvidia-smi profile name from a MIG instance
// type name (e.g. "mig.1g.10gb" → "1g.10gb"). Returns "" for non-MIG types.
func MIGProfileFromType(instanceType string) string {
if !IsMIGType(instanceType) {
profile, ok := strings.CutPrefix(instanceType, migTypePrefix)
if !ok {
return ""
}
return strings.TrimPrefix(instanceType, "mig.")
return profile
}
// GenerateMIGTypes returns one InstanceTypeInfo per unique MIG profile. Instance
@@ -247,7 +251,7 @@ func MIGProfileFromType(instanceType string) string {
func GenerateMIGTypes(profiles []MIGProfileSpec, arch string) map[string]*ec2.InstanceTypeInfo {
types := make(map[string]*ec2.InstanceTypeInfo)
for _, p := range profiles {
name := "mig." + p.Name
name := migTypePrefix + p.Name
if _, exists := types[name]; exists {
continue
}
+2 -2
View File
@@ -48,11 +48,11 @@ func ListIMDSTaps(ctx context.Context, r Runner) ([]IMDSTapEndpoint, error) {
// a port missing it can never be a member of the live set either way, and one
// structurally broken port must not stall every reconcile pass.
ifaceID, ok := row.externalIDs["iface-id"]
if !ok || !strings.HasPrefix(ifaceID, ovsIfaceIDPrefix) {
eniID, prefixed := strings.CutPrefix(ifaceID, ovsIfaceIDPrefix)
if !ok || !prefixed {
slog.Warn("IMDS: skipping IMDS patch port with unexpected iface-id", "port", row.name, "iface_id", ifaceID)
continue
}
eniID := strings.TrimPrefix(ifaceID, ovsIfaceIDPrefix)
taps = append(taps, IMDSTapEndpoint{ENIID: eniID, Endpoint: IMDSEndpointName(eniID)})
}
return taps, nil
@@ -87,6 +87,8 @@ func parseNbdkitCmdline(cmdline []byte) (disc discoveredNbdkit, ok bool) {
args := bytes.Split(bytes.TrimRight(cmdline, "\x00"), []byte{0})
for i := 0; i < len(args); i++ {
arg := string(args[i])
volume, isVolume := strings.CutPrefix(arg, "volume=")
baseDir, isBaseDir := strings.CutPrefix(arg, "base_dir=")
switch {
case arg == "--unix" && i+1 < len(args):
disc.Socket = string(args[i+1])
@@ -96,10 +98,10 @@ func parseNbdkitCmdline(cmdline []byte) (disc discoveredNbdkit, ok bool) {
disc.Port = port
}
i++
case strings.HasPrefix(arg, "volume="):
disc.Volume = strings.TrimPrefix(arg, "volume=")
case strings.HasPrefix(arg, "base_dir="):
disc.BaseDir = strings.TrimPrefix(arg, "base_dir=")
case isVolume:
disc.Volume = volume
case isBaseDir:
disc.BaseDir = baseDir
case strings.HasSuffix(arg, ".so"):
disc.Plugin = arg
}
+3 -2
View File
@@ -194,10 +194,11 @@ func parseSumsFile(body []byte, filename string) (string, error) {
}
case 4:
// BSD-style: "<algo> (<name>) = <hex>". The "=" guard rejects PGP armor lines that happen to tokenise to 4 fields.
if fields[2] != "=" || !strings.HasPrefix(fields[1], "(") || !strings.HasSuffix(fields[1], ")") {
inner, open := strings.CutPrefix(fields[1], "(")
name, closed := strings.CutSuffix(inner, ")")
if fields[2] != "=" || !open || !closed {
continue
}
name := strings.TrimSuffix(strings.TrimPrefix(fields[1], "("), ")")
if name == filename {
return fields[3], nil
}
+2 -3
View File
@@ -56,11 +56,10 @@ func pidFileOwners(runtimeDir string) map[int]string {
return owners
}
for _, entry := range entries {
name := entry.Name()
if !strings.HasSuffix(name, ".pid") {
id, ok := strings.CutSuffix(entry.Name(), ".pid")
if !ok {
continue
}
id := strings.TrimSuffix(name, ".pid")
if pid, err := utils.ReadPidFileFrom(runtimeDir, id); err == nil {
owners[pid] = id
}
+2 -4
View File
@@ -285,10 +285,8 @@ func subjectsOverlap(a, b []string) bool {
// matches anything sharing its prefix; two wildcards match if one prefix
// contains the other.
func subjectMatch(x, y string) bool {
xw := strings.HasSuffix(x, ".*")
yw := strings.HasSuffix(y, ".*")
xp := strings.TrimSuffix(x, ".*")
yp := strings.TrimSuffix(y, ".*")
xp, xw := strings.CutSuffix(x, ".*")
yp, yw := strings.CutSuffix(y, ".*")
switch {
case xw && yw:
return xp == yp || strings.HasPrefix(xp, yp+".") || strings.HasPrefix(yp, xp+".")
+3 -2
View File
@@ -389,10 +389,11 @@ func runGuestChurnRound(t *testing.T, fix *Fixture, instanceID, origType, keyPat
// Bash strips the ".nano" suffix and appends ".small" — same family,
// more RAM at matching vCPU. Avoids xlarge (16 GiB) which the CI host
// can't satisfy.
if !strings.HasSuffix(origType, ".nano") {
family, ok := strings.CutSuffix(origType, ".nano")
if !ok {
t.Fatalf("phase7b: expected discovered instance type to end with .nano, got %q", origType)
}
modifyType := strings.TrimSuffix(origType, ".nano") + ".small"
modifyType := family + ".small"
harness.Detail(t, "from_type", origType, "to_type", modifyType)
// Stop the instance first — ModifyInstanceAttribute on a running