go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/led/job/info_swarming.go (about)

     1  // Copyright 2020 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package job
    16  
    17  import (
    18  	"reflect"
    19  	"time"
    20  
    21  	"google.golang.org/protobuf/proto"
    22  
    23  	"go.chromium.org/luci/common/errors"
    24  	swarmingpb "go.chromium.org/luci/swarming/proto/api_v2"
    25  )
    26  
    27  type swInfo struct {
    28  	*Swarming
    29  }
    30  
    31  var _ Info = swInfo{}
    32  
    33  func (s swInfo) SwarmingHostname() string {
    34  	return s.GetHostname()
    35  }
    36  
    37  func (s swInfo) TaskName() string {
    38  	return s.GetTask().GetName()
    39  }
    40  
    41  func (s swInfo) CurrentIsolated() (*swarmingpb.CASReference, error) {
    42  	casOptions := map[string]*swarmingpb.CASReference{}
    43  	if p := s.GetCasUserPayload(); p.GetDigest().GetHash() != "" {
    44  		casOptions[p.Digest.Hash] = p
    45  	}
    46  
    47  	if sw := s.Swarming; sw != nil {
    48  		for _, slc := range sw.GetTask().GetTaskSlices() {
    49  			input := slc.GetProperties().GetCasInputRoot()
    50  			if input != nil {
    51  				casOptions[input.Digest.GetHash()] = input
    52  			}
    53  		}
    54  	}
    55  	if len(casOptions) > 1 {
    56  		return nil, errors.Reason(
    57  			"Definition contains multiple RBE-CAS inputs: %v", casOptions).Err()
    58  	}
    59  	for _, v := range casOptions {
    60  		return proto.Clone(v).(*swarmingpb.CASReference), nil
    61  	}
    62  	return nil, nil
    63  }
    64  
    65  func (s swInfo) Dimensions() (ExpiringDimensions, error) {
    66  	ldims := logicalDimensions{}
    67  	var totalExpiration time.Duration
    68  	for _, slc := range s.GetTask().GetTaskSlices() {
    69  		exp := time.Duration(slc.ExpirationSecs) * time.Second
    70  		totalExpiration += exp
    71  
    72  		for _, dim := range slc.GetProperties().GetDimensions() {
    73  			ldims.updateDuration(dim.Key, dim.Value, totalExpiration)
    74  		}
    75  	}
    76  	return ldims.toExpiringDimensions(), nil
    77  }
    78  
    79  func (s swInfo) CIPDPkgs() (ret CIPDPkgs, err error) {
    80  	slices := s.GetTask().GetTaskSlices()
    81  	if len(slices) >= 1 {
    82  		if pkgs := slices[0].GetProperties().GetCipdInput().GetPackages(); len(pkgs) > 0 {
    83  			ret = CIPDPkgs{}
    84  			ret.fromList(pkgs)
    85  		}
    86  	}
    87  	if len(slices) > 1 {
    88  		for idx, slc := range slices[1:] {
    89  			pkgDict := CIPDPkgs{}
    90  			pkgDict.fromList(slc.GetProperties().GetCipdInput().GetPackages())
    91  			if !ret.equal(pkgDict) {
    92  				return nil, errors.Reason(
    93  					"slice %d has cipd pkgs which differ from slice 0: %v vs %v",
    94  					idx+1, pkgDict, ret).Err()
    95  			}
    96  		}
    97  	}
    98  	return
    99  }
   100  
   101  func (s swInfo) Env() (ret map[string]string, err error) {
   102  	slices := s.GetTask().GetTaskSlices()
   103  	extractEnv := func(slc *swarmingpb.TaskSlice) (slcEnv map[string]string) {
   104  		if env := slices[0].GetProperties().GetEnv(); len(env) > 0 {
   105  			slcEnv = make(map[string]string, len(env))
   106  			for _, pair := range env {
   107  				slcEnv[pair.Key] = pair.Value
   108  			}
   109  		}
   110  		return
   111  	}
   112  
   113  	if len(slices) >= 1 {
   114  		ret = extractEnv(slices[0])
   115  
   116  		for idx, slc := range slices[1:] {
   117  			if slcEnv := extractEnv(slc); !reflect.DeepEqual(ret, slcEnv) {
   118  				return nil, errors.Reason(
   119  					"slice %d has env which differs from slice 0: %v vs %v",
   120  					idx+1, slcEnv, ret).Err()
   121  			}
   122  		}
   123  	}
   124  	return
   125  }
   126  
   127  func (s swInfo) Priority() int32 {
   128  	return s.GetTask().GetPriority()
   129  }
   130  
   131  func (s swInfo) PrefixPathEnv() (ret []string, err error) {
   132  	slices := s.GetTask().GetTaskSlices()
   133  	if len(slices) >= 1 {
   134  		for _, keyVals := range slices[0].GetProperties().GetEnvPrefixes() {
   135  			if keyVals.Key == "PATH" {
   136  				ret = make([]string, len(keyVals.Value))
   137  				copy(ret, keyVals.Value)
   138  				break
   139  			}
   140  		}
   141  	}
   142  	if len(slices) > 1 {
   143  		for idx, slc := range slices[1:] {
   144  			foundIt := false
   145  			for _, keyVal := range slc.GetProperties().GetEnvPrefixes() {
   146  				if keyVal.Key == "PATH" {
   147  					foundIt = true
   148  					if !reflect.DeepEqual(ret, keyVal.Value) {
   149  						return nil, errors.Reason(
   150  							"slice %d has $PATH env prefixes which differ from slice 0: %v vs %v",
   151  							idx+1, keyVal.Value, ret).Err()
   152  					}
   153  					break
   154  				}
   155  			}
   156  			if !foundIt && len(ret) > 0 {
   157  				return nil, errors.Reason(
   158  					"slice %d has $PATH env prefixes which differ from slice 0: %v vs %v",
   159  					idx+1, []string{}, ret).Err()
   160  			}
   161  		}
   162  	}
   163  	return
   164  }
   165  
   166  func (s swInfo) Tags() (ret []string) {
   167  	if tags := s.GetTask().GetTags(); len(tags) > 0 {
   168  		ret = make([]string, len(tags))
   169  		copy(ret, tags)
   170  	}
   171  	return
   172  }