Beispiel #1
0
func validateHost(url url.URL) error {
	if url.Host == "" {
		return errors.NewNotValid(nil, "URL missing host")
	}

	host, port, err := net.SplitHostPort(url.Host)
	if err != nil {
		return errors.NewNotValid(err, "")
	}

	// Check the host.
	if net.ParseIP(host) == nil {
		if err := validateDomainName(host); err != nil {
			return errors.Trace(err)
		}
	}

	// Check the port.
	if p, err := strconv.Atoi(port); err != nil {
		return errors.NewNotValid(err, fmt.Sprintf("invalid port in host %q", url.Host))
	} else if p <= 0 || p > 0xFFFF {
		return errors.NewNotValid(err, fmt.Sprintf("invalid port in host %q", url.Host))
	}

	return nil
}
Beispiel #2
0
// Validate ensures that the origin is correct.
func (o Origin) Validate() error {
	if o.ControllerUUID == "" {
		return errors.NewNotValid(nil, "empty ControllerUUID")
	}
	if !names.IsValidModel(o.ControllerUUID) {
		return errors.NewNotValid(nil, fmt.Sprintf("ControllerUUID %q not a valid UUID", o.ControllerUUID))
	}

	if o.ModelUUID == "" {
		return errors.NewNotValid(nil, "empty ModelUUID")
	}
	if !names.IsValidModel(o.ModelUUID) {
		return errors.NewNotValid(nil, fmt.Sprintf("ModelUUID %q not a valid UUID", o.ModelUUID))
	}

	if err := o.Type.Validate(); err != nil {
		return errors.Annotate(err, "invalid Type")
	}

	if o.Name == "" && o.Type != OriginTypeUnknown {
		return errors.NewNotValid(nil, "empty Name")
	}
	if err := o.Type.ValidateName(o.Name); err != nil {
		return errors.Annotatef(err, "invalid Name %q", o.Name)
	}

	if !o.Software.isZero() {
		if err := o.Software.Validate(); err != nil {
			return errors.Annotate(err, "invalid Software")
		}
	}

	return nil
}
Beispiel #3
0
func newSizeChecker(size int) func([]byte) error {
	return func(sum []byte) error {
		if len(sum) < size {
			return errors.NewNotValid(nil, "invalid fingerprint (too small)")
		}
		if len(sum) > size {
			return errors.NewNotValid(nil, "invalid fingerprint (too big)")
		}
		return nil
	}
}
Beispiel #4
0
// Validate ensures that the software info is correct.
func (sw Software) Validate() error {
	if sw.PrivateEnterpriseNumber <= 0 {
		return errors.NewNotValid(nil, "missing PrivateEnterpriseNumber")
	}
	if sw.Name == "" {
		return errors.NewNotValid(nil, "empty Name")
	}
	if sw.Version == version.Zero {
		return errors.NewNotValid(nil, "empty Version")
	}
	return nil
}
Beispiel #5
0
Datei: audit.go Projekt: bac/juju
// Validate ensures that the entry considers itself to be in a
// complete and valid state.
func (e AuditEntry) Validate() error {
	if e.JujuServerVersion == version.Zero {
		return errors.NewNotValid(errors.NotAssignedf("JujuServerVersion"), "")
	}
	if e.ModelUUID == "" {
		return errors.NewNotValid(errors.NotAssignedf("ModelUUID"), "")
	}
	if utils.IsValidUUIDString(e.ModelUUID) == false {
		return errors.NotValidf("ModelUUID")
	}
	if e.Timestamp.IsZero() {
		return errors.NewNotValid(errors.NotAssignedf("Timestamp"), "")
	}
	if e.Timestamp.Location() != time.UTC {
		return errors.NewNotValid(errors.NotValidf("Timestamp"), "must be set to UTC")
	}
	if e.RemoteAddress == "" {
		return errors.NewNotValid(errors.NotAssignedf("RemoteAddress"), "")
	}
	if e.OriginType == "" {
		return errors.NewNotValid(errors.NotAssignedf("OriginType"), "")
	}
	if e.OriginName == "" {
		return errors.NewNotValid(errors.NotAssignedf("OriginName"), "")
	}
	if e.Operation == "" {
		return errors.NewNotValid(errors.NotAssignedf("Operation"), "")
	}

	// Data remains unchecked as it is always optional.

	return nil
}
Beispiel #6
0
func (s CredentialSchema) processFileAttrValue(
	field NamedCredentialAttr, resultMap map[string]interface{}, newAttrs map[string]string,
	readFile func(string) ([]byte, error),
) error {
	name := field.Name
	if fieldVal, ok := resultMap[name]; ok {
		if _, ok := resultMap[field.FileAttr]; ok {
			return errors.NotValidf(
				"specifying both %q and %q",
				name, field.FileAttr,
			)
		}
		newAttrs[name] = fieldVal.(string)
		return nil
	}
	fieldVal, ok := resultMap[field.FileAttr]
	if !ok {
		return errors.NewNotValid(nil, fmt.Sprintf(
			"either %q or %q must be specified",
			name, field.FileAttr,
		))
	}
	data, err := readFile(fieldVal.(string))
	if err != nil {
		return errors.Annotatef(err, "reading file for %q", name)
	}
	if len(data) == 0 {
		return errors.NotValidf("empty file for %q", name)
	}
	newAttrs[name] = string(data)
	return nil
}
Beispiel #7
0
func (c *registerCommand) promptControllerName(store jujuclient.ClientStore, suggestedName string, stderr io.Writer, stdin io.Reader) (string, error) {
	_, err := store.ControllerByName(suggestedName)
	if err == nil {
		fmt.Fprintf(stderr, errControllerConflicts, suggestedName)
		suggestedName = ""
	}
	var setMsg string
	setMsg = "Enter a name for this controller: "
	if suggestedName != "" {
		setMsg = fmt.Sprintf("Enter a name for this controller [%s]: ",
			suggestedName)
	}
	fmt.Fprintf(stderr, setMsg)
	defer stderr.Write([]byte{'\n'})
	name, err := c.readLine(stdin)
	if err != nil {
		return "", errors.Trace(err)
	}
	name = strings.TrimSpace(name)
	if name == "" && suggestedName == "" {
		return "", errors.NewNotValid(nil, "you must specify a non-empty controller name")
	}
	if name == "" && suggestedName != "" {
		return suggestedName, nil
	}
	return name, nil
}
Beispiel #8
0
func (m *Machine) validateLinkLayerDeviceParent(args *LinkLayerDeviceArgs) error {
	hostMachineID, parentDeviceName, err := parseLinkLayerDeviceParentNameAsGlobalKey(args.ParentName)
	if err != nil {
		return errors.Trace(err)
	} else if hostMachineID == "" {
		// Not a global key, so validate as usual.
		if err := m.validateParentDeviceNameWhenNotAGlobalKey(args); errors.IsNotFound(err) {
			return errors.NewNotValid(err, "ParentName not valid")
		} else if err != nil {
			return errors.Trace(err)
		}
		return nil
	}
	ourParentMachineID, hasParent := m.ParentId()
	if !hasParent {
		// Using global key for ParentName not allowed for non-container machine
		// devices.
		return errors.NotValidf("ParentName %q for non-container machine %q", args.ParentName, m.Id())
	}
	if hostMachineID != ourParentMachineID {
		// ParentName as global key only allowed when the key's machine ID is
		// the container's host machine.
		return errors.NotValidf("ParentName %q on non-host machine %q", args.ParentName, hostMachineID)
	}

	err = m.verifyHostMachineParentDeviceExistsAndIsABridgeDevice(hostMachineID, parentDeviceName)
	return errors.Trace(err)
}
Beispiel #9
0
func (m *Machine) validateSetDevicesAddressesArgs(args *LinkLayerDeviceAddress) error {
	if args.CIDRAddress == "" {
		return errors.NotValidf("empty CIDRAddress")
	}
	if _, _, err := net.ParseCIDR(args.CIDRAddress); err != nil {
		return errors.NewNotValid(err, "CIDRAddress")
	}

	if args.DeviceName == "" {
		return errors.NotValidf("empty DeviceName")
	}
	if !IsValidLinkLayerDeviceName(args.DeviceName) {
		logger.Warningf(
			"address %q on machine %q has invalid device name %q (using anyway)",
			args.CIDRAddress, m.Id(), args.DeviceName,
		)
	}
	if err := m.verifyDeviceAlreadyExists(args.DeviceName); err != nil {
		return errors.Trace(err)
	}

	if !IsValidAddressConfigMethod(string(args.ConfigMethod)) {
		return errors.NotValidf("ConfigMethod %q", args.ConfigMethod)
	}

	if args.GatewayAddress != "" {
		if ip := net.ParseIP(args.GatewayAddress); ip == nil {
			return errors.NotValidf("GatewayAddress %q", args.GatewayAddress)
		}
	}

	return nil
}
Beispiel #10
0
func (c *setDefaultRegionCommand) Run(ctxt *cmd.Context) error {
	cloudDetails, err := cloudOrProvider(c.cloud, jujucloud.CloudByName)
	if err != nil {
		return err
	}
	if len(cloudDetails.Regions) == 0 {
		return errors.Errorf("cloud %s has no regions", c.cloud)
	}
	if !hasRegion(c.region, cloudDetails.Regions) {
		var regionNames []string
		for _, r := range cloudDetails.Regions {
			regionNames = append(regionNames, r.Name)
		}
		return errors.NewNotValid(
			nil,
			fmt.Sprintf("region %q for cloud %s not valid, valid regions are %s",
				c.region, c.cloud, strings.Join(regionNames, ", ")))
	}
	var cred *jujucloud.CloudCredential
	cred, err = c.store.CredentialForCloud(c.cloud)
	if errors.IsNotFound(err) {
		cred = &jujucloud.CloudCredential{}
	} else if err != nil {
		return err
	}
	cred.DefaultRegion = c.region
	if err := c.store.UpdateCredential(c.cloud, *cred); err != nil {
		return err
	}
	ctxt.Infof("Default region in %s set to %q.", c.cloud, c.region)
	return nil
}
Beispiel #11
0
// parseResourceFileArg converts the provided string into a name and
// filename. The string must be in the "<name>=<filename>" format.
func parseResourceFileArg(raw string) (name string, filename string, _ error) {
	vals := strings.SplitN(raw, "=", 2)
	if len(vals) < 2 {
		msg := fmt.Sprintf("expected name=path format")
		return "", "", errors.NewNotValid(nil, msg)
	}

	name, filename = vals[0], vals[1]
	if name == "" {
		return "", "", errors.NewNotValid(nil, "missing resource name")
	}
	if filename == "" {
		return "", "", errors.NewNotValid(nil, "missing filename")
	}
	return name, filename, nil
}
Beispiel #12
0
func validateScheme(url url.URL) error {
	switch url.Scheme {
	case "https":
	default:
		return errors.NewNotValid(nil, fmt.Sprintf("unsupported URL scheme %q", url.Scheme))
	}
	return nil
}
Beispiel #13
0
// AddSpace creates and returns a new space.
func (st *State) AddSpace(name string, providerId network.Id, subnets []string, isPublic bool) (newSpace *Space, err error) {
	defer errors.DeferredAnnotatef(&err, "adding space %q", name)
	if !names.IsValidSpace(name) {
		return nil, errors.NewNotValid(nil, "invalid space name")
	}

	spaceDoc := spaceDoc{
		Life:       Alive,
		Name:       name,
		IsPublic:   isPublic,
		ProviderId: string(providerId),
	}
	newSpace = &Space{doc: spaceDoc, st: st}

	ops := []txn.Op{{
		C:      spacesC,
		Id:     name,
		Assert: txn.DocMissing,
		Insert: spaceDoc,
	}}

	if providerId != "" {
		ops = append(ops, st.networkEntityGlobalKeyOp("space", providerId))
	}

	for _, subnetId := range subnets {
		// TODO:(mfoord) once we have refcounting for subnets we should
		// also assert that the refcount is zero as moving the space of a
		// subnet in use is not permitted.
		ops = append(ops, txn.Op{
			C:      subnetsC,
			Id:     subnetId,
			Assert: txn.DocExists,
			Update: bson.D{{"$set", bson.D{{"space-name", name}}}},
		})
	}

	if err := st.runTransaction(ops); err == txn.ErrAborted {
		if _, err := st.Space(name); err == nil {
			return nil, errors.AlreadyExistsf("space %q", name)
		}
		for _, subnetId := range subnets {
			if _, err := st.Subnet(subnetId); errors.IsNotFound(err) {
				return nil, err
			}
		}
		if err := newSpace.Refresh(); err != nil {
			if errors.IsNotFound(err) {
				return nil, errors.Errorf("ProviderId %q not unique", providerId)
			}
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(err)
	} else if err != nil {
		return nil, err
	}
	return newSpace, nil
}
Beispiel #14
0
// Validate ensures that the origin type is correct.
func (ot OriginType) Validate() error {
	// As noted above, typedef'ing int means that the use of int
	// literals or explicit type conversion could result in unsupported
	// "enum" values. Otherwise OriginType would not need this method.
	if _, ok := originTypes[ot]; !ok {
		return errors.NewNotValid(nil, "unsupported origin type")
	}
	return nil
}
Beispiel #15
0
func (s *FingerprintSuite) TestNewFingerprintInvalid(c *gc.C) {
	expected, _ := newFingerprint(c, "spamspamspam")
	failure := errors.NewNotValid(nil, "bogus!!!")
	s.stub.SetErrors(failure)

	_, err := hash.NewFingerprint(expected, s.validate)

	s.stub.CheckCallNames(c, "validate")
	c.Check(errors.Cause(err), gc.Equals, failure)
}
func (m *Machine) validateParentDeviceNameWhenNotAGlobalKey(args *LinkLayerDeviceArgs) error {
	if !IsValidLinkLayerDeviceName(args.ParentName) {
		return errors.NotValidf("ParentName %q", args.ParentName)
	}
	if args.Name == args.ParentName {
		return errors.NewNotValid(nil, "Name and ParentName must be different")
	}
	if err := m.verifyParentDeviceExists(args.ParentName); err != nil {
		return errors.Trace(err)
	}
	return nil
}
Beispiel #17
0
// ValidateName ensures that the given origin name is valid within the
// context of the origin type.
func (ot OriginType) ValidateName(name string) error {
	switch ot {
	case OriginTypeUnknown:
		if name != "" {
			return errors.NewNotValid(nil, "origin name must not be set if type is unknown")
		}
	case OriginTypeUser:
		if !names.IsValidUser(name) {
			return errors.NewNotValid(nil, "bad user name")
		}
	case OriginTypeMachine:
		if !names.IsValidMachine(name) {
			return errors.NewNotValid(nil, "bad machine name")
		}
	case OriginTypeUnit:
		if !names.IsValidUnit(name) {
			return errors.NewNotValid(nil, "bad unit name")
		}
	}
	return nil
}
Beispiel #18
0
func (m *Machine) prepareOneSetLinkLayerDeviceArgs(args *LinkLayerDeviceArgs, pendingNames set.Strings) (_ *linkLayerDeviceDoc, err error) {
	defer errors.DeferredAnnotatef(&err, "invalid device %q", args.Name)

	if err := m.validateSetLinkLayerDeviceArgs(args); err != nil {
		return nil, errors.Trace(err)
	}

	if pendingNames.Contains(args.Name) {
		return nil, errors.NewNotValid(nil, "Name specified more than once")
	}

	return m.newLinkLayerDeviceDocFromArgs(args), nil
}
Beispiel #19
0
func (c *registerCommand) promptControllerName(stderr io.Writer, stdin io.Reader) (string, error) {
	fmt.Fprintf(stderr, "Please set a name for this controller: ")
	defer stderr.Write([]byte{'\n'})
	name, err := c.readLine(stdin)
	if err != nil {
		return "", errors.Trace(err)
	}
	name = strings.TrimSpace(name)
	if name == "" {
		return "", errors.NewNotValid(nil, "you must specify a non-empty controller name")
	}
	return name, nil
}
Beispiel #20
0
// Validate ensures that the spec is valid.
func (res Resource) Validate() error {
	// TODO(ericsnow) Ensure that the "placeholder" fields are not set
	// if IsLocalPlaceholder() returns true (and that they *are* set
	// otherwise)? Also ensure an "upload" origin in the "placeholder"
	// case?

	if err := res.Resource.Validate(); err != nil {
		return errors.Annotate(err, "bad info")
	}

	if res.ServiceID == "" {
		return errors.NewNotValid(nil, "missing service ID")
	}

	// TODO(ericsnow) Require that Username be set if timestamp is?

	if res.Timestamp.IsZero() && res.Username != "" {
		return errors.NewNotValid(nil, "missing timestamp")
	}

	return nil
}
Beispiel #21
0
// validateCloudCredentials checks that the supplied cloud credentials are
// valid for use with the controller's cloud, and returns a set of txn.Ops
// to assert the same in a transaction. The map keys are the cloud credential
// IDs.
//
// TODO(rogpeppe) We're going to a lot of effort here to assert that a
// cloud's auth types haven't changed since we looked at them a moment
// ago, but we don't support changing a cloud's definition currently and
// it's not clear that doing so would be a good idea, as changing a
// cloud's auth type would invalidate all existing credentials and would
// usually involve a new provider version and juju binary too, so
// perhaps all this code is unnecessary.
func validateCloudCredentials(
	cloud cloud.Cloud,
	cloudName string,
	credentials map[names.CloudCredentialTag]cloud.Credential,
) ([]txn.Op, error) {
	requiredAuthTypes := make(set.Strings)
	for tag, credential := range credentials {
		if tag.Cloud().Id() != cloudName {
			return nil, errors.NewNotValid(nil, fmt.Sprintf(
				"credential %q for non-matching cloud is not valid (expected %q)",
				tag.Id(), cloudName,
			))
		}
		var found bool
		for _, authType := range cloud.AuthTypes {
			if credential.AuthType() == authType {
				found = true
				break
			}
		}
		if !found {
			return nil, errors.NewNotValid(nil, fmt.Sprintf(
				"credential %q with auth-type %q is not supported (expected one of %q)",
				tag.Id(), credential.AuthType(), cloud.AuthTypes,
			))
		}
		requiredAuthTypes.Add(string(credential.AuthType()))
	}
	ops := make([]txn.Op, len(requiredAuthTypes))
	for i, authType := range requiredAuthTypes.SortedValues() {
		ops[i] = txn.Op{
			C:      cloudsC,
			Id:     cloudName,
			Assert: bson.D{{"auth-types", authType}},
		}
	}
	return ops, nil
}
Beispiel #22
0
// AddSpace creates and returns a new space.
func (st *State) AddSpace(name string, subnets []string, isPublic bool) (newSpace *Space, err error) {
	defer errors.DeferredAnnotatef(&err, "adding space %q", name)
	if !names.IsValidSpace(name) {
		return nil, errors.NewNotValid(nil, "invalid space name")
	}

	spaceID := st.docID(name)
	spaceDoc := spaceDoc{
		DocID:    spaceID,
		EnvUUID:  st.EnvironUUID(),
		Life:     Alive,
		Name:     name,
		IsPublic: isPublic,
	}
	newSpace = &Space{doc: spaceDoc, st: st}

	ops := []txn.Op{{
		C:      spacesC,
		Id:     spaceID,
		Assert: txn.DocMissing,
		Insert: spaceDoc,
	}}

	for _, subnetId := range subnets {
		// TODO:(mfoord) once we have refcounting for subnets we should
		// also assert that the refcount is zero as moving the space of a
		// subnet in use is not permitted.
		ops = append(ops, txn.Op{
			C:      subnetsC,
			Id:     st.docID(subnetId),
			Assert: txn.DocExists,
			Update: bson.D{{"$set", bson.D{{"space-name", name}}}},
		})
	}

	if err := st.runTransaction(ops); err == txn.ErrAborted {
		if _, err := st.Space(name); err == nil {
			return nil, errors.AlreadyExistsf("space %q", name)
		}
		for _, subnetId := range subnets {
			if _, err := st.Subnet(subnetId); errors.IsNotFound(err) {
				return nil, err
			}
		}
	} else if err != nil {
		return nil, err
	}
	return newSpace, nil
}
Beispiel #23
0
// Validate ensures that the location is correct.
func (loc SourceLocation) Validate() error {
	if loc == zero {
		return nil
	}

	// Module may be anything, so there's nothing to check there.

	// Filename may be set with no line number set, but not the other
	// way around.
	if loc.Line >= 0 && loc.Filename == "" {
		return errors.NewNotValid(nil, "Line set but Filename empty")
	}

	return nil
}
Beispiel #24
0
func (m *Machine) validateParentDeviceNameWhenNotAGlobalKey(args *LinkLayerDeviceArgs) error {
	if !IsValidLinkLayerDeviceName(args.ParentName) {
		logger.Warningf(
			"parent link-layer device %q on machine %q has invalid name (using anyway)",
			args.ParentName, m.Id(),
		)
	}
	if args.Name == args.ParentName {
		return errors.NewNotValid(nil, "Name and ParentName must be different")
	}
	if err := m.verifyParentDeviceExists(args.ParentName); err != nil {
		return errors.Trace(err)
	}
	return nil
}
Beispiel #25
0
func (s *BaseSuite) Do(req *http.Request, body io.ReadSeeker, resp interface{}) error {
	s.stub.AddCall("Do", req, body, resp)
	if err := s.stub.NextErr(); err != nil {
		return errors.Trace(err)
	}

	result, ok := resp.(*api.UploadResult)
	if !ok {
		msg := fmt.Sprintf("bad response type %T, expected api.UploadResult", resp)
		return errors.NewNotValid(nil, msg)
	}

	*result = *s.response
	return nil
}
Beispiel #26
0
func (m *ModelManagerAPI) newModelConfig(
	cloudSpec environs.CloudSpec,
	args params.ModelCreateArgs,
	source ConfigSource,
) (*config.Config, error) {
	// For now, we just smash to the two maps together as we store
	// the account values and the model config together in the
	// *config.Config instance.
	joint := make(map[string]interface{})
	for key, value := range args.Config {
		joint[key] = value
	}
	if _, ok := joint["uuid"]; ok {
		return nil, errors.New("uuid is generated, you cannot specify one")
	}
	if args.Name == "" {
		return nil, errors.NewNotValid(nil, "Name must be specified")
	}
	if _, ok := joint[config.NameKey]; ok {
		return nil, errors.New("name must not be specified in config")
	}
	joint[config.NameKey] = args.Name

	baseConfig, err := source.Config()
	if err != nil {
		return nil, errors.Trace(err)
	}

	regionSpec := &environs.RegionSpec{Cloud: cloudSpec.Name, Region: cloudSpec.Region}
	if joint, err = m.state.ComposeNewModelConfig(joint, regionSpec); err != nil {
		return nil, errors.Trace(err)
	}

	creator := modelmanager.ModelConfigCreator{
		Provider: environs.Provider,
		FindTools: func(n version.Number) (tools.List, error) {
			result, err := m.toolsFinder.FindTools(params.FindToolsParams{
				Number: n,
			})
			if err != nil {
				return nil, errors.Trace(err)
			}
			return result.List, nil
		},
	}
	return creator.NewModelConfig(cloudSpec, baseConfig, joint)
}
Beispiel #27
0
func (c *registerCommand) promptNewPassword(stderr io.Writer, stdin io.Reader) (string, error) {
	password, err := c.readPassword("Enter password: "******"", errors.Trace(err)
	}
	if password == "" {
		return "", errors.NewNotValid(nil, "you must specify a non-empty password")
	}
	passwordConfirmation, err := c.readPassword("Confirm password: "******"", errors.Trace(err)
	}
	if password != passwordConfirmation {
		return "", errors.Errorf("passwords do not match")
	}
	return password, nil
}
Beispiel #28
0
// Set implements gnuflag.Value's Set method.
func (m stringMap) Set(s string) error {
	if *m.mapping == nil {
		*m.mapping = map[string]string{}
	}
	// make a copy so the following code is less ugly with dereferencing.
	mapping := *m.mapping

	vals := strings.SplitN(s, "=", 2)
	if len(vals) != 2 {
		return errors.NewNotValid(nil, "badly formatted name value pair: "+s)
	}
	name, value := vals[0], vals[1]
	if _, ok := mapping[name]; ok {
		return errors.Errorf("duplicate name specified: %q", name)
	}
	mapping[name] = value
	return nil
}
Beispiel #29
0
// Validate ensures that the record is correct.
func (rec Record) Validate() error {
	if err := rec.Origin.Validate(); err != nil {
		return errors.Annotate(err, "invalid Origin")
	}

	if rec.Timestamp.IsZero() {
		return errors.NewNotValid(nil, "empty Timestamp")
	}

	// rec.Level may be anything, so we don't check it.

	if err := rec.Location.Validate(); err != nil {
		return errors.Annotate(err, "invalid Location")
	}

	// rec.Message may be anything, so we don't check it.

	return nil
}
Beispiel #30
0
func (d deployUploader) validateResources() error {
	var errs []error
	for _, meta := range d.resources {
		if err := meta.Validate(); err != nil {
			errs = append(errs, err)
		}
	}
	if len(errs) == 1 {
		return errors.Trace(errs[0])
	}
	if len(errs) > 1 {
		msgs := make([]string, len(errs))
		for i, err := range errs {
			msgs[i] = err.Error()
		}
		return errors.NewNotValid(nil, strings.Join(msgs, ", "))
	}
	return nil
}