func (c *InCommand) Run(input concourse.InRequest) (concourse.InResponse, error) { productSlug := input.Source.ProductSlug version, fingerprint, err := versions.SplitIntoVersionAndFingerprint(input.Version.ProductVersion) if err != nil { c.logger.Info("Parsing of fingerprint failed; continuing without it") version = input.Version.ProductVersion fingerprint = "" } c.logger.Info(fmt.Sprintf( "Getting release for product slug: '%s' and product version: '%s'", productSlug, version, )) release, err := c.pivnetClient.GetRelease(productSlug, version) if err != nil { return concourse.InResponse{}, err } if fingerprint != "" { actualFingerprint := release.UpdatedAt if actualFingerprint != fingerprint { return concourse.InResponse{}, fmt.Errorf( "provided fingerprint: '%s' does not match actual fingerprint (from pivnet): '%s' - %s", fingerprint, actualFingerprint, "pivnet does not support downloading old versions of a release", ) } } c.logger.Info(fmt.Sprintf("Accepting EULA for release with ID: %d", release.ID)) err = c.pivnetClient.AcceptEULA(productSlug, release.ID) if err != nil { return concourse.InResponse{}, err } c.logger.Info("Getting product files") releaseProductFiles, err := c.pivnetClient.ProductFilesForRelease(productSlug, release.ID) if err != nil { return concourse.InResponse{}, err } c.logger.Info("Getting file groups") fileGroups, err := c.pivnetClient.FileGroupsForRelease(productSlug, release.ID) if err != nil { return concourse.InResponse{}, err } allProductFiles := releaseProductFiles for _, fg := range fileGroups { allProductFiles = append(allProductFiles, fg.ProductFiles...) } // Get individual product files to obtain metadata that isn't found // in the endpoint for all product files. for i, p := range allProductFiles { allProductFiles[i], err = c.pivnetClient.ProductFileForRelease( productSlug, release.ID, p.ID, ) if err != nil { return concourse.InResponse{}, err } } c.logger.Info("Getting release dependencies") releaseDependencies, err := c.pivnetClient.ReleaseDependencies(productSlug, release.ID) if err != nil { return concourse.InResponse{}, err } c.logger.Info("Getting release upgrade paths") releaseUpgradePaths, err := c.pivnetClient.ReleaseUpgradePaths(productSlug, release.ID) if err != nil { return concourse.InResponse{}, err } c.logger.Info("Downloading files") err = c.downloadFiles(input.Params.Globs, allProductFiles, productSlug, release.ID) if err != nil { return concourse.InResponse{}, err } c.logger.Info("Creating metadata") versionWithFingerprint, err := versions.CombineVersionAndFingerprint(version, fingerprint) mdata := metadata.Metadata{ Release: &metadata.Release{ ID: release.ID, Version: release.Version, ReleaseType: string(release.ReleaseType), ReleaseDate: release.ReleaseDate, Description: release.Description, ReleaseNotesURL: release.ReleaseNotesURL, Availability: release.Availability, Controlled: release.Controlled, ECCN: release.ECCN, LicenseException: release.LicenseException, EndOfSupportDate: release.EndOfSupportDate, EndOfGuidanceDate: release.EndOfGuidanceDate, EndOfAvailabilityDate: release.EndOfAvailabilityDate, }, } if release.EULA != nil { mdata.Release.EULASlug = release.EULA.Slug } for _, pf := range releaseProductFiles { mdata.Release.ProductFiles = append(mdata.Release.ProductFiles, metadata.ReleaseProductFile{ ID: pf.ID, }) } for _, pf := range allProductFiles { mdata.ProductFiles = append(mdata.ProductFiles, metadata.ProductFile{ ID: pf.ID, File: pf.Name, Description: pf.Description, AWSObjectKey: pf.AWSObjectKey, FileType: pf.FileType, FileVersion: pf.FileVersion, MD5: pf.MD5, }) } for _, d := range releaseDependencies { mdata.Dependencies = append(mdata.Dependencies, metadata.Dependency{ Release: metadata.DependentRelease{ ID: d.Release.ID, Version: d.Release.Version, Product: metadata.Product{ ID: d.Release.Product.ID, Name: d.Release.Product.Name, }, }, }) } for _, d := range releaseUpgradePaths { mdata.UpgradePaths = append(mdata.UpgradePaths, metadata.UpgradePath{ ID: d.Release.ID, Version: d.Release.Version, }) } for _, fg := range fileGroups { mfg := metadata.FileGroup{ ID: fg.ID, Name: fg.Name, } for _, pf := range fg.ProductFiles { mfg.ProductFiles = append(mfg.ProductFiles, metadata.FileGroupProductFile{ ID: pf.ID, }) } mdata.FileGroups = append(mdata.FileGroups, mfg) } c.logger.Info("Writing metadata files") err = c.fileWriter.WriteVersionFile(versionWithFingerprint) if err != nil { return concourse.InResponse{}, err } err = c.fileWriter.WriteMetadataYAMLFile(mdata) if err != nil { return concourse.InResponse{}, err } err = c.fileWriter.WriteMetadataJSONFile(mdata) if err != nil { return concourse.InResponse{}, err } concourseMetadata := c.addReleaseMetadata([]concourse.Metadata{}, release) out := concourse.InResponse{ Version: concourse.Version{ ProductVersion: versionWithFingerprint, }, Metadata: concourseMetadata, } return out, nil }
func main() { if version == "" { version = "dev" } logger := log.New(os.Stderr, "", log.LstdFlags|log.Lmicroseconds) logger.Printf("PivNet Resource version: %s", version) if len(os.Args) < 2 { log.Fatalf("not enough args - usage: %s <sources directory>", os.Args[0]) } sourcesDir := os.Args[1] outDir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { log.Fatalln(err) } var input concourse.OutRequest err = json.NewDecoder(os.Stdin).Decode(&input) if err != nil { log.Fatalln(err) } sanitized := concourse.SanitizedSource(input.Source) logger.SetOutput(sanitizer.NewSanitizer(sanitized, os.Stderr)) verbose := false ls := logshim.NewLogShim(logger, logger, verbose) var endpoint string if input.Source.Endpoint != "" { endpoint = input.Source.Endpoint } else { endpoint = pivnet.DefaultHost } clientConfig := pivnet.ClientConfig{ Host: endpoint, Token: input.Source.APIToken, UserAgent: useragent.UserAgent(version, "put", input.Source.ProductSlug), } client := gp.NewClient( clientConfig, ls, ) bucket := input.Source.Bucket if bucket == "" { bucket = defaultBucket } region := input.Source.Region if region == "" { region = defaultRegion } s3Client := s3.NewClient(s3.NewClientConfig{ AccessKeyID: input.Source.AccessKeyID, SecretAccessKey: input.Source.SecretAccessKey, RegionName: region, Bucket: bucket, Stderr: os.Stderr, Logger: ls, }) uploaderClient := uploader.NewClient(uploader.Config{ FilepathPrefix: input.Params.FilepathPrefix, SourcesDir: sourcesDir, Transport: s3Client, }) globber := globs.NewGlobber(globs.GlobberConfig{ FileGlob: input.Params.FileGlob, SourcesDir: sourcesDir, Logger: ls, }) skipUpload := input.Params.FileGlob == "" && input.Params.FilepathPrefix == "" var m metadata.Metadata if input.Params.MetadataFile == "" { log.Fatalf("params.metadata_file must be provided") } metadataFilepath := filepath.Join(sourcesDir, input.Params.MetadataFile) metadataBytes, err := ioutil.ReadFile(metadataFilepath) if err != nil { log.Fatalf("params.metadata_file could not be read: %s", err.Error()) } err = yaml.Unmarshal(metadataBytes, &m) if err != nil { log.Fatalf("params.metadata_file could not be parsed: %s", err.Error()) } err = m.Validate() if err != nil { log.Fatalf("params.metadata_file is invalid: %s", err.Error()) } validation := validator.NewOutValidator(input) semverConverter := semver.NewSemverConverter(ls) md5summer := md5sum.NewFileSummer() f := filter.NewFilter(ls) releaseCreator := release.NewReleaseCreator( client, semverConverter, ls, m, input.Params, input.Source, sourcesDir, input.Source.ProductSlug, ) asyncTimeout := 1 * time.Hour pollFrequency := 5 * time.Second releaseUploader := release.NewReleaseUploader( uploaderClient, client, ls, md5summer, m, sourcesDir, input.Source.ProductSlug, asyncTimeout, pollFrequency, ) releaseUserGroupsUpdater := release.NewUserGroupsUpdater( ls, client, m, input.Source.ProductSlug, ) releaseDependenciesAdder := release.NewReleaseDependenciesAdder( ls, client, m, input.Source.ProductSlug, ) releaseUpgradePathsAdder := release.NewReleaseUpgradePathsAdder( ls, client, m, input.Source.ProductSlug, f, ) releaseFinalizer := release.NewFinalizer( client, ls, input.Params, m, sourcesDir, input.Source.ProductSlug, ) outCmd := out.NewOutCommand(out.OutCommandConfig{ Logger: ls, OutDir: outDir, SourcesDir: sourcesDir, GlobClient: globber, Validation: validation, Creator: releaseCreator, Uploader: releaseUploader, UserGroupsUpdater: releaseUserGroupsUpdater, ReleaseDependenciesAdder: releaseDependenciesAdder, ReleaseUpgradePathsAdder: releaseUpgradePathsAdder, Finalizer: releaseFinalizer, M: m, SkipUpload: skipUpload, }) response, err := outCmd.Run(input) if err != nil { log.Fatalln(err) } err = json.NewEncoder(os.Stdout).Encode(response) if err != nil { log.Fatalln(err) } }
package metadata_test import ( "fmt" "github.com/pivotal-cf/pivnet-resource/metadata" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Metadata", func() { Describe("Validate", func() { var data metadata.Metadata BeforeEach(func() { data = metadata.Metadata{ Release: &metadata.Release{ Version: "1.0.0", ReleaseType: "All In One", EULASlug: "some-other-eula", }, ProductFiles: []metadata.ProductFile{ {File: "hello.txt", Description: "available"}, }, } }) Context("when release is missing", func() { BeforeEach(func() { data.Release = nil })
. "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("ReleaseUpgradePathsAdder", func() { Describe("AddReleaseUpgradePaths", func() { var ( fakeLogger logger.Logger pivnetClient *releasefakes.ReleaseUpgradePathsAdderClient fakeFilter *releasefakes.FakeFilter existingReleases []pivnet.Release filteredReleases []pivnet.Release existingReleasesErr error filterErr error mdata metadata.Metadata productSlug string pivnetRelease pivnet.Release releaseUpgradePathsAdder release.ReleaseUpgradePathsAdder ) BeforeEach(func() { logger := log.New(GinkgoWriter, "", log.LstdFlags) fakeLogger = logshim.NewLogShim(logger, logger, true) pivnetClient = &releasefakes.ReleaseUpgradePathsAdderClient{}