// NewDefaultProcurement returns the default procurement strategy that combines validation // and responsible Mesos resource procurement. c and m are resource quantities written into // k8s api.Pod.Spec's that don't declare resources (all containers in k8s-mesos require cpu // and memory limits). func NewDefaultProcurement(prototype *mesos.ExecutorInfo, eir executorinfo.Registry) Procurement { return AllOrNothingProcurement([]Procurement{ NewNodeProcurement(), NewPodResourcesProcurement(), NewPortsProcurement(), NewExecutorResourceProcurer(prototype.GetResources(), eir), }) }
// initializeStaticPodsSource unzips the data slice into the static-pods directory func (k *Executor) initializeStaticPodsSource(executorInfo *mesos.ExecutorInfo) { if data := executorInfo.GetData(); len(data) > 0 && k.staticPodsConfigPath != "" { log.V(2).Infof("extracting static pods config to %s", k.staticPodsConfigPath) err := podutil.WriteToDir( k.staticPodsFilters.Do(podutil.Gunzip(executorInfo.Data)), k.staticPodsConfigPath, ) if err != nil { log.Errorf("failed to initialize static pod configuration: %v", err) } } }
// compute a hashcode for ExecutorInfo that may be used as a reasonable litmus test // with respect to compatibility across HA schedulers. the intent is that an HA scheduler // should fail-fast if it doesn't pass this test, rather than generating (potentially many) // errors at run-time because a Mesos master decides that the ExecutorInfo generated by a // secondary scheduler doesn't match that of the primary scheduler. // // Note: We intentionally leave out the Resources in this hash because they are // set during procurement and should not lead to a different ExecutorId. // This also means that the Resources do not contribute to offer // compatibility checking. But as we persist and restore the Resources // through node anotation we make sure that the right resources are chosen // during task launch. // // see https://github.com/apache/mesos/blob/0.22.0/src/common/type_utils.cpp#L110 func hash(info *mesos.ExecutorInfo) uint64 { // !!! we specifically do NOT include: // - Framework ID because it's a value that's initialized too late for us to use // - Executor ID because it's a value that includes a copy of this hash buf := &bytes.Buffer{} buf.WriteString(info.GetName()) buf.WriteString(info.GetSource()) buf.Write(info.Data) if info.Command != nil { buf.WriteString(info.Command.GetValue()) buf.WriteString(info.Command.GetUser()) buf.WriteString(strconv.FormatBool(info.Command.GetShell())) if sz := len(info.Command.Arguments); sz > 0 { x := make([]string, sz) copy(x, info.Command.Arguments) sort.Strings(x) for _, item := range x { buf.WriteString(item) } } if vars := info.Command.Environment.GetVariables(); len(vars) > 0 { names := []string{} e := make(map[string]string) for _, v := range vars { if name := v.GetName(); name != "" { names = append(names, name) e[name] = v.GetValue() } } sort.Strings(names) for _, n := range names { buf.WriteString(n) buf.WriteString("=") buf.WriteString(e[n]) } } if uris := info.Command.GetUris(); len(uris) > 0 { su := []string{} for _, uri := range uris { su = append(su, fmt.Sprintf("%s%t%t", uri.GetValue(), uri.GetExecutable(), uri.GetExtract())) } sort.Strings(su) for _, uri := range su { buf.WriteString(uri) } } //TODO(jdef) add support for Container } table := crc64.MakeTable(crc64.ECMA) return crc64.Checksum(buf.Bytes(), table) }
func annotationsFor(ei *mesos.ExecutorInfo) (annotations map[string]string, err error) { annotations = map[string]string{} if ei == nil { return } var buf bytes.Buffer if err = executorinfo.EncodeResources(&buf, ei.GetResources()); err != nil { return } annotations[meta.ExecutorIdKey] = ei.GetExecutorId().GetValue() annotations[meta.ExecutorResourcesKey] = buf.String() return }
func nodeInfo(si *mesos.SlaveInfo, ei *mesos.ExecutorInfo) NodeInfo { var executorCPU, executorMem float64 // get executor resources if ei != nil { for _, r := range ei.GetResources() { if r == nil || r.GetType() != mesos.Value_SCALAR { continue } switch r.GetName() { case "cpus": executorCPU += r.GetScalar().GetValue() case "mem": executorMem += r.GetScalar().GetValue() } } } // get resource capacity of the node ni := NodeInfo{} for _, r := range si.GetResources() { if r == nil || r.GetType() != mesos.Value_SCALAR { continue } switch r.GetName() { case "cpus": // We intentionally take the floor of executorCPU because cores are integers // and we would loose a complete cpu here if the value is <1. // TODO(sttts): switch to float64 when "Machine Allocables" are implemented ni.Cores += int(r.GetScalar().GetValue()) case "mem": ni.Mem += int64(r.GetScalar().GetValue()) * 1024 * 1024 } } // TODO(sttts): subtract executorCPU/Mem from static pod resources before subtracting them from the capacity ni.Cores -= int(executorCPU) ni.Mem -= int64(executorMem) * 1024 * 1024 return ni }
func setCommandArgument(ei *mesos.ExecutorInfo, flag, value string, create bool) { argv := []string{} overwrite := false if ei.Command != nil && ei.Command.Arguments != nil { argv = ei.Command.Arguments for i, arg := range argv { if strings.HasPrefix(arg, flag+"=") { overwrite = true argv[i] = flag + "=" + value break } } } if !overwrite && create { argv = append(argv, flag+"="+value) if ei.Command == nil { ei.Command = &mesos.CommandInfo{} } ei.Command.Arguments = argv } }