get.porter.sh/porter@v1.3.0/pkg/porter/porter.go (about) 1 package porter 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strings" 8 "sync" 9 10 "get.porter.sh/porter/pkg/build" 11 "get.porter.sh/porter/pkg/build/buildkit" 12 "get.porter.sh/porter/pkg/cache" 13 cnabtooci "get.porter.sh/porter/pkg/cnab/cnab-to-oci" 14 cnabprovider "get.porter.sh/porter/pkg/cnab/provider" 15 "get.porter.sh/porter/pkg/config" 16 "get.porter.sh/porter/pkg/mixin" 17 "get.porter.sh/porter/pkg/plugins" 18 "get.porter.sh/porter/pkg/secrets" 19 secretsplugin "get.porter.sh/porter/pkg/secrets/pluginstore" 20 "get.porter.sh/porter/pkg/signing" 21 signingplugin "get.porter.sh/porter/pkg/signing/pluginstore" 22 "get.porter.sh/porter/pkg/storage" 23 "get.porter.sh/porter/pkg/storage/migrations" 24 storageplugin "get.porter.sh/porter/pkg/storage/pluginstore" 25 "get.porter.sh/porter/pkg/templates" 26 "get.porter.sh/porter/pkg/tracing" 27 "github.com/hashicorp/go-multierror" 28 ) 29 30 // Porter is the logic behind the porter client. 31 type Porter struct { 32 *config.Config 33 34 // builder is loaded dynamically when unset, this allows us to 35 // use the configuration that is set after we create Porter, 36 // or to switch it out for tests. 37 builder build.Builder 38 39 Cache cache.BundleCache 40 Credentials storage.CredentialSetProvider 41 Parameters storage.ParameterSetProvider 42 Sanitizer *storage.Sanitizer 43 Installations storage.InstallationProvider 44 Registry cnabtooci.RegistryProvider 45 Templates *templates.Templates 46 Mixins mixin.MixinProvider 47 Plugins plugins.PluginProvider 48 CNAB cnabprovider.CNABProvider 49 Secrets secrets.Store 50 Storage storage.Provider 51 Signer signing.Signer 52 } 53 54 // New porter client, initialized with useful defaults. 55 func New() *Porter { 56 c := config.New() 57 storage := storage.NewPluginAdapter(storageplugin.NewStore(c)) 58 secretStorage := secrets.NewPluginAdapter(secretsplugin.NewStore(c)) 59 signer := signing.NewPluginAdapter(signingplugin.NewSigner(c)) 60 return NewFor(c, storage, secretStorage, signer) 61 } 62 63 func NewFor(c *config.Config, store storage.Store, secretStorage secrets.Store, signer signing.Signer) *Porter { 64 cache := cache.New(c) 65 66 storageManager := migrations.NewManager(c, store) 67 installationStorage := storage.NewInstallationStore(storageManager) 68 credStorage := storage.NewCredentialStore(storageManager, secretStorage) 69 paramStorage := storage.NewParameterStore(storageManager, secretStorage) 70 sanitizerService := storage.NewSanitizer(paramStorage, secretStorage) 71 72 storageManager.Initialize(sanitizerService) // we have a bit of a dependency problem here that it would be great to figure out eventually 73 74 return &Porter{ 75 Config: c, 76 Cache: cache, 77 Storage: storageManager, 78 Installations: installationStorage, 79 Credentials: credStorage, 80 Parameters: paramStorage, 81 Secrets: secretStorage, 82 Registry: cnabtooci.NewRegistry(c.Context), 83 Templates: templates.NewTemplates(c), 84 Mixins: mixin.NewPackageManager(c), 85 Plugins: plugins.NewPackageManager(c), 86 CNAB: cnabprovider.NewRuntime(c, installationStorage, credStorage, paramStorage, secretStorage, sanitizerService), 87 Sanitizer: sanitizerService, 88 Signer: signer, 89 } 90 } 91 92 // Used to warn just a single time when Porter starts up. 93 // Connect is called more than once, and this helps us validate certain things, like build flags, a single time only. 94 var initWarnings sync.Once 95 96 // Connect initializes Porter for use and must be called before other Porter methods. 97 // It is the responsibility of the caller to also call Close when done with Porter. 98 func (p *Porter) Connect(ctx context.Context) (context.Context, error) { 99 initWarnings.Do(func() { 100 // Check if this is a special dev build that will trace sensitive data and strongly warn people 101 if tracing.IsTraceSensitiveAttributesEnabled() { 102 fmt.Fprintln(p.Err, "🚨 WARNING! This is a custom developer build of Porter with the traceSensitiveAttributes build flag set. "+ 103 "Porter will include sensitive data, such as parameters and credentials, in the telemetry trace data. "+ 104 "This build flag should only be used for local development only. "+ 105 "If you didn't intend to use a custom build of Porter with this flag enabled, reinstall Porter using the official builds from https://porter.sh/install.") 106 } 107 }) 108 109 // Load the config file and replace any referenced secrets 110 return p.Config.Load(ctx, func(innerCtx context.Context, secret string) (string, error) { 111 value, err := p.Secrets.Resolve(innerCtx, "secret", secret) 112 if err != nil { 113 if strings.Contains(err.Error(), "invalid value source: secret") { 114 return "", errors.New("No secret store account is configured") 115 } 116 return "", err 117 } 118 return value, nil 119 }) 120 } 121 122 // Close releases resources used by Porter before terminating the application. 123 func (p *Porter) Close() error { 124 // Shutdown our plugins 125 var bigErr *multierror.Error 126 127 err := p.Secrets.Close() 128 if err != nil { 129 bigErr = multierror.Append(bigErr, err) 130 } 131 132 err = p.Storage.Close() 133 if err != nil { 134 bigErr = multierror.Append(bigErr, err) 135 } 136 137 err = p.Config.Close() 138 if err != nil { 139 bigErr = multierror.Append(bigErr, err) 140 } 141 142 err = p.Signer.Close() 143 if err != nil { 144 bigErr = multierror.Append(bigErr, err) 145 } 146 147 return bigErr.ErrorOrNil() 148 } 149 150 // GetBuilder creates a Builder based on the current configuration. 151 func (p *Porter) GetBuilder(ctx context.Context) build.Builder { 152 log := tracing.LoggerFromContext(ctx) 153 154 if p.builder == nil { 155 driver := p.GetBuildDriver() 156 switch driver { 157 case config.BuildDriverBuildkit: 158 // supported, yay! 159 case config.BuildDriverDocker: 160 log.Warn("The docker build driver is no longer supported. Using buildkit instead.") 161 default: 162 log.Warnf("Unsupported build driver: %s. Using buildkit instead.", driver) 163 } 164 p.builder = buildkit.NewBuilder(p.Config) 165 } 166 return p.builder 167 }