func nonResourceRuleCovers(allowedPaths sets.String, requestedPaths sets.String) bool { if allowedPaths.Has(authorizationapi.NonResourceAll) { return true } for requestedPath := range requestedPaths { // If we contain the exact path, we're good if allowedPaths.Has(requestedPath) { continue } // See if one of the rules has a wildcard that allows this path prefixMatch := false for allowedPath := range allowedPaths { if strings.HasSuffix(allowedPath, "*") { if strings.HasPrefix(requestedPath, allowedPath[0:len(allowedPath)-1]) { return true } } } if !prefixMatch { return false } } return true }
func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventRecorder) (filtered []*api.Pod) { names := sets.String{} for i, pod := range pods { var errlist field.ErrorList if errs := validation.ValidatePod(pod); len(errs) != 0 { errlist = append(errlist, errs...) // If validation fails, don't trust it any further - // even Name could be bad. } else { name := kubecontainer.GetPodFullName(pod) if names.Has(name) { // TODO: when validation becomes versioned, this gets a bit // more complicated. errlist = append(errlist, field.Duplicate(field.NewPath("metadata", "name"), pod.Name)) } else { names.Insert(name) } } if len(errlist) > 0 { name := bestPodIdentString(pod) err := errlist.ToAggregate() glog.Warningf("Pod[%d] (%s) from %s failed validation, ignoring: %v", i+1, name, source, err) recorder.Eventf(pod, api.EventTypeWarning, kubecontainer.FailedValidation, "Error validating pod %s from %s, ignoring: %v", name, source, err) continue } filtered = append(filtered, pod) } return }
func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, interfacesFunc meta.VersionInterfacesFunc, importPathPrefix string, ignoredKinds, rootScoped sets.String) *meta.DefaultRESTMapper { mapper := meta.NewDefaultRESTMapper(defaultGroupVersions, interfacesFunc) // enumerate all supported versions, get the kinds, and register with the mapper how to address // our resources. for _, gv := range defaultGroupVersions { for kind, oType := range Scheme.KnownTypes(gv.String()) { gvk := gv.WithKind(kind) // TODO: Remove import path prefix check. // We check the import path prefix because we currently stuff both "api" and "extensions" objects // into the same group within Scheme since Scheme has no notion of groups yet. if !strings.HasPrefix(oType.PkgPath(), importPathPrefix) || ignoredKinds.Has(kind) { continue } scope := meta.RESTScopeNamespace if rootScoped.Has(kind) { scope = meta.RESTScopeRoot } mapper.Add(gvk, scope, false) } } return mapper }
// edgeHop checks the links of the given backend by executing an edge hop. // It fixes broken links. func (b *Backends) edgeHop(be *compute.BackendService, igs []*compute.InstanceGroup) error { beIGs := sets.String{} for _, beToIG := range be.Backends { beIGs.Insert(beToIG.Group) } igLinks := sets.String{} for _, igToBE := range igs { igLinks.Insert(igToBE.SelfLink) } if beIGs.IsSuperset(igLinks) { return nil } glog.Infof("Backend %v has a broken edge, expected igs %+v, current igs %+v", be.Name, igLinks.List(), beIGs.List()) newBackends := []*compute.Backend{} for _, b := range getBackendsForIGs(igs) { if !beIGs.Has(b.Group) { newBackends = append(newBackends, b) } } be.Backends = append(be.Backends, newBackends...) if err := b.cloud.UpdateBackendService(be); err != nil { return err } return nil }
func NewDefaultRESTMapper(group string, groupVersionStrings []string, interfacesFunc meta.VersionInterfacesFunc, importPathPrefix string, ignoredKinds, rootScoped sets.String) *meta.DefaultRESTMapper { mapper := meta.NewDefaultRESTMapper(group, groupVersionStrings, interfacesFunc) // enumerate all supported versions, get the kinds, and register with the mapper how to address // our resources. for _, gvString := range groupVersionStrings { gv, err := unversioned.ParseGroupVersion(gvString) // TODO stop panicing when the types are fixed if err != nil { panic(err) } if gv.Group != group { panic(fmt.Sprintf("%q does not match the expect %q", gv.Group, group)) } for kind, oType := range Scheme.KnownTypes(gv.String()) { // TODO: Remove import path prefix check. // We check the import path prefix because we currently stuff both "api" and "extensions" objects // into the same group within Scheme since Scheme has no notion of groups yet. if !strings.HasPrefix(oType.PkgPath(), importPathPrefix) || ignoredKinds.Has(kind) { continue } scope := meta.RESTScopeNamespace if rootScoped.Has(kind) { scope = meta.RESTScopeRoot } mapper.Add(scope, kind, gv.String(), false) } } return mapper }
// mergeGroupMeta takes an lhs and an rhs GroupMeta, then builds a resulting GroupMeta that contains the // merged information. Order of merging matters: lhs wins. func mergeGroupMeta(lhs, rhs apimachinery.GroupMeta) apimachinery.GroupMeta { merged := apimachinery.GroupMeta{} merged.GroupVersion = lhs.GroupVersion merged.SelfLinker = lhs.SelfLinker knownGVs := sets.String{} for _, lhsGV := range lhs.GroupVersions { knownGVs.Insert(lhsGV.String()) merged.GroupVersions = append(merged.GroupVersions, lhsGV) } for _, rhsGV := range lhs.GroupVersions { if knownGVs.Has(rhsGV.String()) { continue } merged.GroupVersions = append(merged.GroupVersions, rhsGV) } merged.RESTMapper = meta.MultiRESTMapper(append([]meta.RESTMapper{}, lhs.RESTMapper, rhs.RESTMapper)) merged.InterfacesFor = func(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) { if ret, err := lhs.InterfacesFor(version); err == nil { return ret, nil } return rhs.InterfacesFor(version) } return merged }
func (c *MasterConfig) defaultAPIGroupVersion() *apiserver.APIGroupVersion { var restMapper meta.MultiRESTMapper seenGroups := sets.String{} for _, gv := range registered.EnabledVersions() { if seenGroups.Has(gv.Group) { continue } seenGroups.Insert(gv.Group) groupMeta, err := registered.Group(gv.Group) if err != nil { continue } restMapper = meta.MultiRESTMapper(append(restMapper, groupMeta.RESTMapper)) } statusMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{kubeapiv1.SchemeGroupVersion}, registered.GroupOrDie(kapi.GroupName).InterfacesFor) statusMapper.Add(kubeapiv1.SchemeGroupVersion.WithKind("Status"), meta.RESTScopeRoot) restMapper = meta.MultiRESTMapper(append(restMapper, statusMapper)) return &apiserver.APIGroupVersion{ Root: OpenShiftAPIPrefix, Mapper: restMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: registered.GroupOrDie("").SelfLinker, Admit: c.AdmissionControl, Context: c.getRequestContextMapper(), SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{}, } }
func (m *DefaultRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) { kinds, err := m.KindsFor(resource) if err != nil { return unversioned.GroupVersionKind{}, err } // TODO for each group, choose the most preferred (first) version. This keeps us consistent with code today. // eventually, we'll need a RESTMapper that is aware of what's available server-side and deconflicts that with // user preferences oneKindPerGroup := []unversioned.GroupVersionKind{} groupsAdded := sets.String{} for _, kind := range kinds { if groupsAdded.Has(kind.Group) { continue } oneKindPerGroup = append(oneKindPerGroup, kind) groupsAdded.Insert(kind.Group) } if len(oneKindPerGroup) == 1 { return oneKindPerGroup[0], nil } return unversioned.GroupVersionKind{}, fmt.Errorf("%v is ambiguous, got: %v", resource, kinds) }
func (r *templateRouter) FilterNamespaces(namespaces sets.String) { r.lock.Lock() defer r.lock.Unlock() if len(namespaces) == 0 { r.state = make(map[string]ServiceAliasConfig) r.serviceUnits = make(map[string]ServiceUnit) } for k := range r.serviceUnits { // TODO: the id of a service unit should be defined inside this class, not passed in from the outside // remove the leak of the abstraction when we refactor this code ns := strings.SplitN(k, "/", 2)[0] if namespaces.Has(ns) { continue } delete(r.serviceUnits, k) } for k := range r.state { ns := strings.SplitN(k, "_", 2)[0] if namespaces.Has(ns) { continue } delete(r.state, k) } }
func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventRecorder) (filtered []*api.Pod) { names := sets.String{} for i, pod := range pods { var errlist []error if errs := validation.ValidatePod(pod); len(errs) != 0 { errlist = append(errlist, errs...) // If validation fails, don't trust it any further - // even Name could be bad. } else { name := kubecontainer.GetPodFullName(pod) if names.Has(name) { errlist = append(errlist, fielderrors.NewFieldDuplicate("name", pod.Name)) } else { names.Insert(name) } } if len(errlist) > 0 { name := bestPodIdentString(pod) err := utilerrors.NewAggregate(errlist) glog.Warningf("Pod[%d] (%s) from %s failed validation, ignoring: %v", i+1, name, source, err) recorder.Eventf(pod, "FailedValidation", "Error validating pod %s from %s, ignoring: %v", name, source, err) continue } filtered = append(filtered, pod) } return }
// nameMatches checks to see if the resourceName of the action is in a the specified whitelist. An empty whitelist indicates that any name is allowed. // An empty string in the whitelist should only match the action's resourceName if the resourceName itself is empty string. This behavior allows for the // combination of a whitelist for gets in the same rule as a list that won't have a resourceName. I don't recommend writing such a rule, but we do // handle it like you'd expect: white list is respected for gets while not preventing the list you explicitly asked for. func (a DefaultAuthorizationAttributes) nameMatches(allowedResourceNames sets.String) bool { if len(allowedResourceNames) == 0 { return true } return allowedResourceNames.Has(a.GetResourceName()) }
func (t *tcShaper) nextClassID() (int, error) { data, err := t.e.Command("tc", "class", "show", "dev", t.iface).CombinedOutput() if err != nil { return -1, err } scanner := bufio.NewScanner(bytes.NewBuffer(data)) classes := sets.String{} for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) // skip empty lines if len(line) == 0 { continue } parts := strings.Split(line, " ") // expected tc line: // class htb 1:1 root prio 0 rate 1000Kbit ceil 1000Kbit burst 1600b cburst 1600b if len(parts) != 14 { return -1, fmt.Errorf("unexpected output from tc: %s (%v)", scanner.Text(), parts) } classes.Insert(parts[2]) } // Make sure it doesn't go forever for nextClass := 1; nextClass < 10000; nextClass++ { if !classes.Has(fmt.Sprintf("1:%d", nextClass)) { return nextClass, nil } } // This should really never happen return -1, fmt.Errorf("exhausted class space, please try again") }
// Print formats and prints the give PodDiff. func (p PodDiff) String(ignorePhases sets.String) string { ret := "" for name, info := range p { if ignorePhases.Has(info.phase) { continue } if info.phase == nonExist { ret += fmt.Sprintf("Pod %v was deleted, had phase %v and host %v\n", name, info.oldPhase, info.oldHostname) continue } phaseChange, hostChange := false, false msg := fmt.Sprintf("Pod %v ", name) if info.oldPhase != info.phase { phaseChange = true if info.oldPhase == nonExist { msg += fmt.Sprintf("in phase %v ", info.phase) } else { msg += fmt.Sprintf("went from phase: %v -> %v ", info.oldPhase, info.phase) } } if info.oldHostname != info.hostname { hostChange = true if info.oldHostname == nonExist || info.oldHostname == "" { msg += fmt.Sprintf("assigned host %v ", info.hostname) } else { msg += fmt.Sprintf("went from host: %v -> %v ", info.oldHostname, info.hostname) } } if phaseChange || hostChange { ret += msg + "\n" } } return ret }
// Pass ports=nil for all ports. func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string { if len(endpoints.Subsets) == 0 { return "<none>" } list := []string{} max := 3 more := false count := 0 for i := range endpoints.Subsets { ss := &endpoints.Subsets[i] for i := range ss.Ports { port := &ss.Ports[i] if ports == nil || ports.Has(port.Name) { for i := range ss.Addresses { if len(list) == max { more = true } addr := &ss.Addresses[i] if !more { list = append(list, fmt.Sprintf("%s:%d", addr.IP, port.Port)) } count++ } } } } ret := strings.Join(list, ",") if more { return fmt.Sprintf("%s + %d more...", ret, count-max) } return ret }
func (w *userProjectWatcher) GroupMembershipChanged(namespaceName string, users, groups sets.String) { if !w.visibleNamespaces.Has("*") && !w.visibleNamespaces.Has(namespaceName) { // this user is scoped to a level that shouldn't see this update return } hasAccess := users.Has(w.user.GetName()) || groups.HasAny(w.user.GetGroups()...) _, known := w.knownProjects[namespaceName] switch { // this means that we were removed from the project case !hasAccess && known: delete(w.knownProjects, namespaceName) select { case w.cacheIncoming <- watch.Event{ Type: watch.Deleted, Object: projectutil.ConvertNamespace(&kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: namespaceName}}), }: default: // remove the watcher so that we wont' be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("delete notification timeout") } case hasAccess: namespace, err := w.projectCache.GetNamespace(namespaceName) if err != nil { utilruntime.HandleError(err) return } event := watch.Event{ Type: watch.Added, Object: projectutil.ConvertNamespace(namespace), } // if we already have this in our list, then we're getting notified because the object changed if lastResourceVersion, known := w.knownProjects[namespaceName]; known { event.Type = watch.Modified // if we've already notified for this particular resourceVersion, there's no work to do if lastResourceVersion == namespace.ResourceVersion { return } } w.knownProjects[namespaceName] = namespace.ResourceVersion select { case w.cacheIncoming <- event: default: // remove the watcher so that we won't be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("add notification timeout") } } }
func intersection(s1 sets.String, s2 sets.String) sets.String { out := sets.String{} for a := range s1 { if s2.Has(a) { out.Insert(a) } } return out }
// TODO move upstream func intersection(s1 sets.String, s2 sets.String) sets.String { result := sets.NewString() for key := range s1 { if s2.Has(key) { result.Insert(key) } } return result }
// Returns pods missing from summary. func podsMissingFromSummary(s stats.Summary, expectedPods sets.String) sets.String { expectedPods = sets.StringKeySet(expectedPods) for _, pod := range s.Pods { if expectedPods.Has(pod.PodRef.Name) { expectedPods.Delete(pod.PodRef.Name) } } return expectedPods }
func findKnownValue(parts []string, valueOptions sets.String) int { for i := range parts { if valueOptions.Has(parts[i]) { return i } } return -1 }
func (w *userProjectWatcher) GroupMembershipChanged(namespaceName string, latestUsers, lastestGroups, removedUsers, removedGroups, addedUsers, addedGroups sets.String) { hasAccess := latestUsers.Has(w.username) || lastestGroups.HasAny(w.groups...) removed := !hasAccess && (removedUsers.Has(w.username) || removedGroups.HasAny(w.groups...)) switch { case removed: if _, known := w.knownProjects[namespaceName]; !known { return } delete(w.knownProjects, namespaceName) select { case w.cacheIncoming <- watch.Event{ Type: watch.Deleted, Object: projectutil.ConvertNamespace(&kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: namespaceName}}), }: default: // remove the watcher so that we wont' be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("delete notification timeout") } case hasAccess: namespace, err := w.projectCache.GetNamespace(namespaceName) if err != nil { utilruntime.HandleError(err) return } event := watch.Event{ Type: watch.Added, Object: projectutil.ConvertNamespace(namespace), } // if we already have this in our list, then we're getting notified because the object changed if lastResourceVersion, known := w.knownProjects[namespaceName]; known { event.Type = watch.Modified // if we've already notified for this particular resourceVersion, there's no work to do if lastResourceVersion == namespace.ResourceVersion { return } } w.knownProjects[namespaceName] = namespace.ResourceVersion select { case w.cacheIncoming <- event: default: // remove the watcher so that we won't be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("add notification timeout") } } }
// filterUnmountedVolumes adds each element of expectedVolumes that is not in // mountedVolumes to a list of unmountedVolumes and returns it. func filterUnmountedVolumes( mountedVolumes sets.String, expectedVolumes []string) []string { unmountedVolumes := []string{} for _, expectedVolume := range expectedVolumes { if !mountedVolumes.Has(expectedVolume) { unmountedVolumes = append(unmountedVolumes, expectedVolume) } } return unmountedVolumes }
// PodMatchesTermsNamespaceAndSelector returns true if the given <pod> // matches the namespace and selector defined by <affinityPod>`s <term>. func PodMatchesTermsNamespaceAndSelector(pod *v1.Pod, namespaces sets.String, selector labels.Selector) bool { if len(namespaces) != 0 && !namespaces.Has(pod.Namespace) { return false } if !selector.Matches(labels.Set(pod.Labels)) { return false } return true }
// purgeDeletedNamespaces will remove all namespaces enumerated in a reviewRecordStore that are not in the namespace set func purgeDeletedNamespaces(namespaceSet *sets.String, userSubjectRecordStore cache.Store, groupSubjectRecordStore cache.Store, reviewRecordStore cache.Store) { reviewRecordItems := reviewRecordStore.List() for i := range reviewRecordItems { reviewRecord := reviewRecordItems[i].(*reviewRecord) if !namespaceSet.Has(reviewRecord.namespace) { deleteNamespaceFromSubjects(userSubjectRecordStore, reviewRecord.users, reviewRecord.namespace) deleteNamespaceFromSubjects(groupSubjectRecordStore, reviewRecord.groups, reviewRecord.namespace) reviewRecordStore.Delete(reviewRecord) } } }
func hostInDomainList(host string, domains sets.String) bool { if domains.Has(host) { return true } if idx := strings.IndexRune(host, '.'); idx > 0 { return hostInDomainList(host[idx+1:], domains) } return false }
// diagnoseMissingEndpoints prints debug information about the endpoints that // are NOT in the given list of foundEndpoints. These are the endpoints we // expected a response from. func (config *NetworkingTestConfig) diagnoseMissingEndpoints(foundEndpoints sets.String) { for _, e := range config.EndpointPods { if foundEndpoints.Has(e.Name) { continue } framework.Logf("\nOutput of kubectl describe pod %v/%v:\n", e.Namespace, e.Name) desc, _ := framework.RunKubectl( "describe", "pod", e.Name, fmt.Sprintf("--namespace=%v", e.Namespace)) framework.Logf(desc) } }
func hasExactlyTheseProjects(list *projectapi.ProjectList, projects sets.String) error { if len(list.Items) != len(projects) { return fmt.Errorf("expected %v, got %v", projects, list.Items) } for _, project := range list.Items { if !projects.Has(project.Name) { return fmt.Errorf("expected %v, got %v", projects, list.Items) } } return nil }
// BasicLongRunningRequestCheck returns true if the given request has one of the specified verbs or one of the specified subresources func BasicLongRunningRequestCheck(longRunningVerbs, longRunningSubresources sets.String) LongRunningRequestCheck { return func(r *http.Request, requestInfo *apiserverrequest.RequestInfo) bool { if longRunningVerbs.Has(requestInfo.Verb) { return true } if requestInfo.IsResourceRequest && longRunningSubresources.Has(requestInfo.Subresource) { return true } return false } }
// ipamGarbageCollection will release unused IPs from dead containers that // the CNI plugin was never notified had died. openshift-sdn uses the CNI // host-local IPAM plugin, which stores allocated IPs in a file in // /var/lib/cni/network. Each file in this directory has as its name the // allocated IP address of the container, and as its contents the container ID. // This routine looks for container IDs that are not reported as running by the // container runtime, and releases each one's IPAM allocation. func (m *podManager) ipamGarbageCollection() { glog.V(2).Infof("Starting IP garbage collection") const ipamDir string = "/var/lib/cni/networks/openshift-sdn" files, err := ioutil.ReadDir(ipamDir) if err != nil { glog.Errorf("Failed to list files in CNI host-local IPAM store %v: %v", ipamDir, err) return } // gather containerIDs for allocated ips ipContainerIdMap := make(map[string]string) for _, file := range files { // skip non checkpoint file if ip := net.ParseIP(file.Name()); ip == nil { continue } content, err := ioutil.ReadFile(filepath.Join(ipamDir, file.Name())) if err != nil { glog.Errorf("Failed to read file %v: %v", file, err) } ipContainerIdMap[file.Name()] = strings.TrimSpace(string(content)) } // gather infra container IDs of current running Pods runningContainerIDs := ksets.String{} pods, err := m.getNonExitedPods() if err != nil { glog.Errorf("Failed to get pods: %v", err) return } for _, pod := range pods { containerID, err := m.host.GetRuntime().GetPodContainerID(pod) if err != nil { glog.Warningf("Failed to get infra containerID of %q/%q: %v", pod.Namespace, pod.Name, err) continue } runningContainerIDs.Insert(strings.TrimSpace(containerID.ID)) } // release leaked ips for ip, containerID := range ipContainerIdMap { // if the container is not running, release IP if runningContainerIDs.Has(containerID) { continue } glog.V(2).Infof("Releasing IP %q allocated to %q.", ip, containerID) m.ipamDel(containerID) } }
func isAPIResourceRequest(apiPrefixes sets.String, req *http.Request) bool { // Slice the first / of the path off (in apiRoots they're stored w/o leading /) parts := strings.Split(req.URL.Path, "/")[1:] // Paths with only one fragment won't have a prefix. for i := 1; i < len(parts); i++ { prefix := strings.Join(parts[:i], "/") if apiPrefixes.Has(prefix) { return true } } return false }
// FilterPodsByNameSpaces filters the pods based the given list of namespaces, // empty set of namespaces means all namespaces. func FilterPodsByNameSpaces(names sets.String, pods []*api.Pod) []*api.Pod { if len(pods) == 0 || len(names) == 0 { return pods } result := []*api.Pod{} for _, pod := range pods { if names.Has(pod.Namespace) { result = append(result, pod) } } return result }