github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/container/registry.go (about) 1 package container 2 3 import ( 4 "fmt" 5 "regexp" 6 "strings" 7 8 "github.com/distribution/reference" 9 "github.com/pkg/errors" 10 11 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 12 ) 13 14 var escapeRegex = regexp.MustCompile(`[/:@]`) 15 16 func escapeName(s string) string { 17 return string(escapeRegex.ReplaceAll([]byte(s), []byte("_"))) 18 } 19 20 // IsEmptyRegistry returns true if the object is nil or has no Host. 21 func IsEmptyRegistry(reg *v1alpha1.RegistryHosting) bool { 22 if reg == nil || reg.Host == "" { 23 return true 24 } 25 return false 26 } 27 28 // RegistryFromCluster determines the registry that should be used for pushing 29 // & pulling Tilt-built images. 30 // 31 // If the v1alpha1.Cluster object is not in a healthy state, an error is 32 // returned. 33 // 34 // If the v1alpha1.Cluster object is healthy and provides local registry 35 // metadata, that will be used. 36 // 37 // Otherwise, if the v1alpha1.Cluster object is healthy and does not provide 38 // local registry metadata but a default registry for the cluster is defined 39 // (typically via `default_registry` in the Tiltfile), the default registry 40 // will be used. 41 // 42 // As a fallback, an empty registry will be returned, which indicates that _no_ 43 // registry rewriting should occur and Tilt should push and pull images to the 44 // registry as specified by the configuration ref (e.g. what's passed in to 45 // `docker_build` or `custom_build`). 46 func RegistryFromCluster(cluster *v1alpha1.Cluster) (*v1alpha1.RegistryHosting, error) { 47 if cluster == nil { 48 return nil, nil 49 } 50 51 if cluster.Status.Error != "" { 52 // if the Cluster has not been initialized, we have not had a chance to 53 // read the local cluster info from it yet 54 return nil, fmt.Errorf("cluster not ready: %s", cluster.Status.Error) 55 } 56 57 if cluster.Status.Registry != nil { 58 return cluster.Status.Registry.DeepCopy(), nil 59 } 60 61 if cluster.Spec.DefaultRegistry != nil { 62 // no local registry is configured for this cluster, so use the default 63 return cluster.Spec.DefaultRegistry.DeepCopy(), nil 64 } 65 66 return nil, nil 67 } 68 69 // replaceRegistry produces a new image name that is in the specified registry. 70 // The name might be ugly, favoring uniqueness and simplicity and assuming that the prettiness of ephemeral dev image 71 // names is not that important. 72 func replaceRegistry(defaultReg string, rs RefSelector, singleName string) (reference.Named, error) { 73 if defaultReg == "" { 74 return rs.AsNamedOnly(), nil 75 } 76 77 // Sometimes users get confused and put the local registry name in the YAML. 78 // No need to replace the registry in that case. 79 // https://github.com/tilt-dev/tilt/issues/4911 80 if strings.HasPrefix(rs.RefFamiliarName(), fmt.Sprintf("%s/", defaultReg)) { 81 return rs.AsNamedOnly(), nil 82 } 83 84 // validate the ref produced 85 newRefString := "" 86 if singleName == "" { 87 newRefString = fmt.Sprintf("%s/%s", defaultReg, escapeName(rs.RefFamiliarName())) 88 } else { 89 newRefString = fmt.Sprintf("%s/%s", defaultReg, singleName) 90 } 91 92 newRef, err := reference.ParseNamed(newRefString) 93 if err != nil { 94 return nil, errors.Wrapf(err, "Error parsing %s after applying default registry %s", newRefString, defaultReg) 95 } 96 97 return newRef, nil 98 } 99 100 // ReplaceRegistryForLocalRef returns a new reference using the target local 101 // registry (as seen from the user). 102 func ReplaceRegistryForLocalRef(rs RefSelector, reg *v1alpha1.RegistryHosting) (reference.Named, error) { 103 var host, singleName string 104 if !IsEmptyRegistry(reg) { 105 host = reg.Host 106 singleName = reg.SingleName 107 } 108 return replaceRegistry(host, rs, singleName) 109 } 110 111 // ReplaceRegistryForContainerRuntimeRef returns a new reference using the target local 112 // registry (as seen from the container runtime). 113 func ReplaceRegistryForContainerRuntimeRef(rs RefSelector, reg *v1alpha1.RegistryHosting) (reference.Named, error) { 114 var host, singleName string 115 if !IsEmptyRegistry(reg) { 116 host = reg.HostFromContainerRuntime 117 if host == "" { 118 host = reg.Host 119 } 120 singleName = reg.SingleName 121 } 122 return replaceRegistry(host, rs, singleName) 123 }