github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/actor/v7action/package.go (about)

     1  package v7action
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/cli/actor/actionerror"
     9  	"code.cloudfoundry.org/cli/actor/sharedaction"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    12  	"code.cloudfoundry.org/cli/resources"
    13  	log "github.com/sirupsen/logrus"
    14  )
    15  
    16  const (
    17  	DefaultFolderPermissions      = 0755
    18  	DefaultArchiveFilePermissions = 0744
    19  )
    20  
    21  type DockerImageCredentials struct {
    22  	Path     string
    23  	Username string
    24  	Password string
    25  }
    26  
    27  func (actor Actor) CreateDockerPackageByApplication(appGUID string, dockerImageCredentials DockerImageCredentials) (resources.Package, Warnings, error) {
    28  	inputPackage := resources.Package{
    29  		Type: constant.PackageTypeDocker,
    30  		Relationships: resources.Relationships{
    31  			constant.RelationshipTypeApplication: resources.Relationship{GUID: appGUID},
    32  		},
    33  		DockerImage:    dockerImageCredentials.Path,
    34  		DockerUsername: dockerImageCredentials.Username,
    35  		DockerPassword: dockerImageCredentials.Password,
    36  	}
    37  	pkg, warnings, err := actor.CloudControllerClient.CreatePackage(inputPackage)
    38  	return resources.Package(pkg), Warnings(warnings), err
    39  }
    40  
    41  func (actor Actor) CreateDockerPackageByApplicationNameAndSpace(appName string, spaceGUID string, dockerImageCredentials DockerImageCredentials) (resources.Package, Warnings, error) {
    42  	app, getWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID)
    43  	if err != nil {
    44  		return resources.Package{}, getWarnings, err
    45  	}
    46  	pkg, warnings, err := actor.CreateDockerPackageByApplication(app.GUID, dockerImageCredentials)
    47  	return pkg, append(getWarnings, warnings...), err
    48  }
    49  
    50  func (actor Actor) CreateAndUploadBitsPackageByApplicationNameAndSpace(appName string, spaceGUID string, bitsPath string) (resources.Package, Warnings, error) {
    51  	app, allWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID)
    52  	if err != nil {
    53  		return resources.Package{}, allWarnings, err
    54  	}
    55  
    56  	if bitsPath == "" {
    57  		bitsPath, err = os.Getwd()
    58  		if err != nil {
    59  			return resources.Package{}, allWarnings, err
    60  		}
    61  	}
    62  
    63  	info, err := os.Stat(bitsPath)
    64  	if err != nil {
    65  		return resources.Package{}, allWarnings, err
    66  	}
    67  
    68  	var fileResources []sharedaction.Resource
    69  	if info.IsDir() {
    70  		fileResources, err = actor.SharedActor.GatherDirectoryResources(bitsPath)
    71  	} else {
    72  		fileResources, err = actor.SharedActor.GatherArchiveResources(bitsPath)
    73  	}
    74  	if err != nil {
    75  		return resources.Package{}, allWarnings, err
    76  	}
    77  
    78  	// potentially match resources here in the future
    79  
    80  	var archivePath string
    81  	if info.IsDir() {
    82  		archivePath, err = actor.SharedActor.ZipDirectoryResources(bitsPath, fileResources)
    83  	} else {
    84  		archivePath, err = actor.SharedActor.ZipArchiveResources(bitsPath, fileResources)
    85  	}
    86  	if err != nil {
    87  		os.RemoveAll(archivePath)
    88  		return resources.Package{}, allWarnings, err
    89  	}
    90  	defer os.RemoveAll(archivePath)
    91  
    92  	inputPackage := resources.Package{
    93  		Type: constant.PackageTypeBits,
    94  		Relationships: resources.Relationships{
    95  			constant.RelationshipTypeApplication: resources.Relationship{GUID: app.GUID},
    96  		},
    97  	}
    98  
    99  	pkg, warnings, err := actor.CloudControllerClient.CreatePackage(inputPackage)
   100  	allWarnings = append(allWarnings, warnings...)
   101  	if err != nil {
   102  		return resources.Package{}, allWarnings, err
   103  	}
   104  
   105  	_, warnings, err = actor.CloudControllerClient.UploadPackage(pkg, archivePath)
   106  	allWarnings = append(allWarnings, warnings...)
   107  	if err != nil {
   108  		return resources.Package{}, allWarnings, err
   109  	}
   110  
   111  	for pkg.State != constant.PackageReady &&
   112  		pkg.State != constant.PackageFailed &&
   113  		pkg.State != constant.PackageExpired {
   114  		time.Sleep(actor.Config.PollingInterval())
   115  		pkg, warnings, err = actor.CloudControllerClient.GetPackage(pkg.GUID)
   116  		allWarnings = append(allWarnings, warnings...)
   117  		if err != nil {
   118  			return resources.Package{}, allWarnings, err
   119  		}
   120  	}
   121  
   122  	if pkg.State == constant.PackageFailed {
   123  		return resources.Package{}, allWarnings, actionerror.PackageProcessingFailedError{}
   124  	} else if pkg.State == constant.PackageExpired {
   125  		return resources.Package{}, allWarnings, actionerror.PackageProcessingExpiredError{}
   126  	}
   127  
   128  	updatedPackage, updatedWarnings, err := actor.PollPackage(resources.Package(pkg))
   129  	return updatedPackage, append(allWarnings, updatedWarnings...), err
   130  }
   131  
   132  func (actor Actor) GetNewestReadyPackageForApplication(app resources.Application) (resources.Package, Warnings, error) {
   133  	ccv3Packages, warnings, err := actor.CloudControllerClient.GetPackages(
   134  		ccv3.Query{
   135  			Key:    ccv3.AppGUIDFilter,
   136  			Values: []string{app.GUID},
   137  		},
   138  		ccv3.Query{
   139  			Key:    ccv3.StatesFilter,
   140  			Values: []string{string(constant.PackageReady)},
   141  		},
   142  		ccv3.Query{
   143  			Key:    ccv3.OrderBy,
   144  			Values: []string{ccv3.CreatedAtDescendingOrder},
   145  		},
   146  	)
   147  
   148  	if err != nil {
   149  		return resources.Package{}, Warnings(warnings), err
   150  	}
   151  
   152  	if len(ccv3Packages) == 0 {
   153  		return resources.Package{}, Warnings(warnings), actionerror.NoEligiblePackagesError{AppName: app.Name}
   154  	}
   155  
   156  	return resources.Package(ccv3Packages[0]), Warnings(warnings), nil
   157  }
   158  
   159  // GetApplicationPackages returns a list of package of an app.
   160  func (actor *Actor) GetApplicationPackages(appName string, spaceGUID string) ([]resources.Package, Warnings, error) {
   161  	app, allWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID)
   162  	if err != nil {
   163  		return nil, allWarnings, err
   164  	}
   165  
   166  	ccv3Packages, warnings, err := actor.CloudControllerClient.GetPackages(
   167  		ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{app.GUID}},
   168  		ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.CreatedAtDescendingOrder}},
   169  	)
   170  	allWarnings = append(allWarnings, warnings...)
   171  	if err != nil {
   172  		return nil, allWarnings, err
   173  	}
   174  
   175  	var packages []resources.Package
   176  	for _, ccv3Package := range ccv3Packages {
   177  		packages = append(packages, resources.Package(ccv3Package))
   178  	}
   179  
   180  	return packages, allWarnings, nil
   181  }
   182  
   183  func (actor Actor) CreateBitsPackageByApplication(appGUID string) (resources.Package, Warnings, error) {
   184  	inputPackage := resources.Package{
   185  		Type: constant.PackageTypeBits,
   186  		Relationships: resources.Relationships{
   187  			constant.RelationshipTypeApplication: resources.Relationship{GUID: appGUID},
   188  		},
   189  	}
   190  
   191  	pkg, warnings, err := actor.CloudControllerClient.CreatePackage(inputPackage)
   192  	if err != nil {
   193  		return resources.Package{}, Warnings(warnings), err
   194  	}
   195  
   196  	return resources.Package(pkg), Warnings(warnings), err
   197  }
   198  
   199  func (actor Actor) UploadBitsPackage(pkg resources.Package, matchedResources []sharedaction.V3Resource, newResources io.Reader, newResourcesLength int64) (resources.Package, Warnings, error) {
   200  	apiResources := make([]ccv3.Resource, 0, len(matchedResources)) // Explicitly done to prevent nils
   201  
   202  	for _, resource := range matchedResources {
   203  		apiResources = append(apiResources, ccv3.Resource(resource))
   204  	}
   205  
   206  	appPkg, warnings, err := actor.CloudControllerClient.UploadBitsPackage(resources.Package(pkg), apiResources, newResources, newResourcesLength)
   207  	return resources.Package(appPkg), Warnings(warnings), err
   208  }
   209  
   210  // PollPackage returns a package of an app.
   211  func (actor Actor) PollPackage(pkg resources.Package) (resources.Package, Warnings, error) {
   212  	var allWarnings Warnings
   213  
   214  	for pkg.State != constant.PackageReady && pkg.State != constant.PackageFailed && pkg.State != constant.PackageExpired {
   215  		time.Sleep(actor.Config.PollingInterval())
   216  		ccPkg, warnings, err := actor.CloudControllerClient.GetPackage(pkg.GUID)
   217  		log.WithFields(log.Fields{
   218  			"package_guid": pkg.GUID,
   219  			"state":        pkg.State,
   220  		}).Debug("polling package state")
   221  
   222  		allWarnings = append(allWarnings, warnings...)
   223  		if err != nil {
   224  			return resources.Package{}, allWarnings, err
   225  		}
   226  
   227  		pkg = resources.Package(ccPkg)
   228  	}
   229  
   230  	if pkg.State == constant.PackageFailed {
   231  		return resources.Package{}, allWarnings, actionerror.PackageProcessingFailedError{}
   232  	} else if pkg.State == constant.PackageExpired {
   233  		return resources.Package{}, allWarnings, actionerror.PackageProcessingExpiredError{}
   234  	}
   235  
   236  	return pkg, allWarnings, nil
   237  }
   238  
   239  func (actor Actor) CopyPackage(sourceApp resources.Application, targetApp resources.Application) (resources.Package, Warnings, error) {
   240  	var allWarnings Warnings
   241  	sourcePkg, warnings, err := actor.GetNewestReadyPackageForApplication(sourceApp)
   242  	allWarnings = append(allWarnings, warnings...)
   243  	if err != nil {
   244  		return resources.Package{}, allWarnings, err
   245  	}
   246  	targetPkg, ccv3Warnings, err := actor.CloudControllerClient.CopyPackage(sourcePkg.GUID, targetApp.GUID)
   247  	allWarnings = append(allWarnings, ccv3Warnings...)
   248  	if err != nil {
   249  		return resources.Package{}, allWarnings, err
   250  	}
   251  
   252  	readyPackage, warnings, err := actor.PollPackage(resources.Package(targetPkg))
   253  	allWarnings = append(allWarnings, warnings...)
   254  	if err != nil {
   255  		return resources.Package{}, allWarnings, err
   256  	}
   257  
   258  	return readyPackage, allWarnings, nil
   259  }