// NewConn returns a new Conn that uses the // given environment. The environment must have already // been bootstrapped. func NewConn(environ environs.Environ) (*Conn, error) { info, _, err := environ.StateInfo() if err != nil { return nil, err } password := environ.Config().AdminSecret() if password == "" { return nil, fmt.Errorf("cannot connect without admin-secret") } err = environs.CheckEnvironment(environ) if err != nil { return nil, err } info.Password = password opts := state.DefaultDialOpts() st, err := state.Open(info, opts, environs.NewStatePolicy()) if errors.IsUnauthorized(err) { logger.Infof("authorization error while connecting to state server; retrying") // We can't connect with the administrator password,; // perhaps this was the first connection and the // password has not been changed yet. info.Password = utils.UserPasswordHash(password, utils.CompatSalt) // We try for a while because we might succeed in // connecting to mongo before the state has been // initialized and the initial password set. for a := redialStrategy.Start(); a.Next(); { st, err = state.Open(info, opts, environs.NewStatePolicy()) if !errors.IsUnauthorized(err) { break } } if err != nil { return nil, err } if err := st.SetAdminMongoPassword(password); err != nil { return nil, err } } else if err != nil { return nil, err } conn := &Conn{ Environ: environ, State: st, } if err := conn.updateSecrets(); err != nil { conn.Close() return nil, fmt.Errorf("unable to push secrets: %v", err) } return conn, nil }
// ServerError returns an error suitable for returning to an API // client, with an error code suitable for various kinds of errors // generated in packages outside the API. func ServerError(err error) *params.Error { if err == nil { return nil } code, ok := singletonCode(err) switch { case ok: case errors.IsUnauthorized(err): code = params.CodeUnauthorized case errors.IsNotFound(err): code = params.CodeNotFound case errors.IsAlreadyExists(err): code = params.CodeAlreadyExists case state.IsNotAssigned(err): code = params.CodeNotAssigned case state.IsHasAssignedUnitsError(err): code = params.CodeHasAssignedUnits case IsNoAddressSetError(err): code = params.CodeNoAddressSet case state.IsNotProvisionedError(err): code = params.CodeNotProvisioned default: code = params.ErrCode(err) } return ¶ms.Error{ Message: err.Error(), Code: code, } }
// GetIndexWithFormat returns a simplestreams index of the specified format. // Exported for testing. func GetIndexWithFormat(source DataSource, indexPath, indexFormat string, requireSigned bool, cloudSpec CloudSpec, params ValueParams) (*IndexReference, error) { data, url, err := fetchData(source, indexPath, requireSigned, params.PublicKey) if err != nil { if errors.IsNotFound(err) || errors.IsUnauthorized(err) { return nil, err } return nil, fmt.Errorf("cannot read index data, %v", err) } var indices Indices err = json.Unmarshal(data, &indices) if err != nil { logger.Errorf("bad JSON index data at URL %q: %v", url, string(data)) return nil, fmt.Errorf("cannot unmarshal JSON index metadata at URL %q: %v", url, err) } if indices.Format != indexFormat { return nil, fmt.Errorf( "unexpected index file format %q, expected %q at URL %q", indices.Format, indexFormat, url) } mirrors, url, err := getMirrorRefs(source, mirrorsPath, requireSigned, params) if err != nil && !errors.IsNotFound(err) && !errors.IsUnauthorized(err) { return nil, fmt.Errorf("cannot load mirror metadata at URL %q: %v", url, err) } indexRef := &IndexReference{ Source: source, Indices: indices, valueParams: params, } // Apply any mirror information to the source. if params.MirrorContentId != "" { mirrorInfo, err := getMirror( source, mirrors, params.DataType, params.MirrorContentId, cloudSpec, requireSigned, params.PublicKey) if err == nil { logger.Debugf("using mirrored products path: %s", path.Join(mirrorInfo.MirrorURL, mirrorInfo.Path)) indexRef.Source = NewURLDataSource("mirror", mirrorInfo.MirrorURL, utils.VerifySSLHostnames) indexRef.MirroredProductsPath = mirrorInfo.Path } else { logger.Debugf("no mirror information available for %s: %v", cloudSpec, err) } } return indexRef, nil }
// GetMirrorMetadataWithFormat returns simplestreams mirror data of the specified format. // Exported for testing. func GetMirrorMetadataWithFormat(source DataSource, mirrorPath, format string, requireSigned bool, publicKey string) (*MirrorMetadata, error) { data, url, err := fetchData(source, mirrorPath, requireSigned, publicKey) if err != nil { if errors.IsNotFound(err) || errors.IsUnauthorized(err) { return nil, err } return nil, fmt.Errorf("cannot read mirror data, %v", err) } var mirrors MirrorMetadata err = json.Unmarshal(data, &mirrors) if err != nil { return nil, fmt.Errorf("cannot unmarshal JSON mirror metadata at URL %q: %v", url, err) } if mirrors.Format != format { return nil, fmt.Errorf("unexpected mirror file format %q, expected %q at URL %q", mirrors.Format, format, url) } return &mirrors, nil }
// getMaybeSignedMetadata returns metadata records matching the specified constraint. func getMaybeSignedMetadata(source DataSource, baseIndexPath string, cons LookupConstraint, signed bool, params ValueParams) ([]interface{}, *ResolveInfo, error) { resolveInfo := &ResolveInfo{} indexPath := baseIndexPath + UnsignedSuffix if signed { indexPath = baseIndexPath + signedSuffix } var items []interface{} indexURL, err := source.URL(indexPath) if err != nil { // Some providers return an error if asked for the URL of a non-existent file. // So the best we can do is use the relative path for the URL when logging messages. indexURL = indexPath } resolveInfo.Source = source.Description() resolveInfo.Signed = signed resolveInfo.IndexURL = indexURL indexRef, err := GetIndexWithFormat(source, indexPath, "index:1.0", signed, cons.Params().CloudSpec, params) if err != nil { if errors.IsNotFound(err) || errors.IsUnauthorized(err) { logger.Debugf("cannot load index %q: %v", indexURL, err) } return nil, resolveInfo, err } logger.Debugf("read metadata index at %q", indexURL) items, err = indexRef.getLatestMetadataWithFormat(cons, "products:1.0", signed) if err != nil { if errors.IsNotFound(err) { logger.Debugf("skipping index because of error getting latest metadata %q: %v", indexURL, err) return nil, resolveInfo, err } if _, ok := err.(*noMatchingProductsError); ok { logger.Debugf("%v", err) } } if indexRef.Source.Description() == "mirror" { resolveInfo.MirrorURL = indexRef.Source.(*urlDataSource).baseURL } return items, resolveInfo, err }
// getMirrorRefs parses and returns a simplestreams mirror reference. func getMirrorRefs(source DataSource, baseMirrorsPath string, requireSigned bool, params ValueParams) (MirrorRefs, string, error) { mirrorsPath := baseMirrorsPath + UnsignedSuffix if requireSigned { mirrorsPath = baseMirrorsPath + signedSuffix } var mirrors MirrorRefs data, url, err := fetchData(source, mirrorsPath, requireSigned, params.PublicKey) if err != nil { if errors.IsNotFound(err) || errors.IsUnauthorized(err) { logger.Debugf("no mirror index file found") return mirrors, url, err } return mirrors, url, fmt.Errorf("cannot read mirrors data, %v", err) } err = json.Unmarshal(data, &mirrors) if err != nil { return mirrors, url, fmt.Errorf("cannot unmarshal JSON mirror metadata at URL %q: %v", url, err) } return mirrors, url, err }