github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/environs/imagemetadata.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package environs 5 6 import ( 7 "sync" 8 9 "github.com/juju/errors" 10 11 "github.com/juju/juju/environs/imagemetadata" 12 "github.com/juju/juju/environs/simplestreams" 13 ) 14 15 type datasourceFuncId struct { 16 id string 17 f ImageDataSourceFunc 18 } 19 20 var ( 21 datasourceFuncsMu sync.RWMutex 22 datasourceFuncs []datasourceFuncId 23 ) 24 25 // ImageDataSourceFunc is a function type that takes an environment and 26 // returns a simplestreams datasource. 27 // 28 // ImageDataSourceFunc will be used in ImageMetadataSources. 29 // Any error satisfying errors.IsNotSupported will be ignored; 30 // any other error will be cause ImageMetadataSources to fail. 31 type ImageDataSourceFunc func(Environ) (simplestreams.DataSource, error) 32 33 // RegisterUserImageDataSourceFunc registers an ImageDataSourceFunc 34 // with the specified id at the start of the search path, overwriting 35 // any function previously registered with the same id. 36 func RegisterUserImageDataSourceFunc(id string, f ImageDataSourceFunc) { 37 datasourceFuncsMu.Lock() 38 defer datasourceFuncsMu.Unlock() 39 for i := range datasourceFuncs { 40 if datasourceFuncs[i].id == id { 41 datasourceFuncs[i].f = f 42 return 43 } 44 } 45 logger.Debugf("new user image datasource registered: %v", id) 46 datasourceFuncs = append([]datasourceFuncId{{id, f}}, datasourceFuncs...) 47 } 48 49 // RegisterImageDataSourceFunc registers an ImageDataSourceFunc 50 // with the specified id, overwriting any function previously registered 51 // with the same id. 52 func RegisterImageDataSourceFunc(id string, f ImageDataSourceFunc) { 53 datasourceFuncsMu.Lock() 54 defer datasourceFuncsMu.Unlock() 55 for i := range datasourceFuncs { 56 if datasourceFuncs[i].id == id { 57 datasourceFuncs[i].f = f 58 return 59 } 60 } 61 logger.Debugf("new model image datasource registered: %v", id) 62 datasourceFuncs = append(datasourceFuncs, datasourceFuncId{id, f}) 63 } 64 65 // UnregisterImageDataSourceFunc unregisters an ImageDataSourceFunc 66 // with the specified id. 67 func UnregisterImageDataSourceFunc(id string) { 68 datasourceFuncsMu.Lock() 69 defer datasourceFuncsMu.Unlock() 70 for i, f := range datasourceFuncs { 71 if f.id == id { 72 head := datasourceFuncs[:i] 73 tail := datasourceFuncs[i+1:] 74 datasourceFuncs = append(head, tail...) 75 return 76 } 77 } 78 } 79 80 // ImageMetadataSources returns the sources to use when looking for 81 // simplestreams image id metadata for the given stream. 82 func ImageMetadataSources(env BootstrapEnviron, dataSourceFactory simplestreams.DataSourceFactory) ([]simplestreams.DataSource, error) { 83 config := env.Config() 84 85 // Add configured and environment-specific datasources. 86 var sources []simplestreams.DataSource 87 if userURL, ok := config.ImageMetadataURL(); ok { 88 publicKey, err := simplestreams.UserPublicSigningKey() 89 if err != nil { 90 return nil, errors.Trace(err) 91 } 92 cfg := simplestreams.Config{ 93 Description: "image-metadata-url", 94 BaseURL: userURL, 95 PublicSigningKey: publicKey, 96 HostnameVerification: config.SSLHostnameVerification(), 97 Priority: simplestreams.SPECIFIC_CLOUD_DATA, 98 } 99 if err := cfg.Validate(); err != nil { 100 return nil, errors.Trace(err) 101 } 102 dataSource := dataSourceFactory.NewDataSource(cfg) 103 sources = append(sources, dataSource) 104 } 105 106 envDataSources, err := environmentDataSources(env) 107 if err != nil { 108 return nil, err 109 } 110 sources = append(sources, envDataSources...) 111 112 if config.ImageMetadataDefaultsDisabled() { 113 logger.Debugf("default image metadata sources are disabled") 114 } else { 115 // Add the official image metadata datasources. 116 officialDataSources, err := imagemetadata.OfficialDataSources(dataSourceFactory, config.ImageStream()) 117 if err != nil { 118 return nil, err 119 } 120 sources = append(sources, officialDataSources...) 121 } 122 123 for _, ds := range sources { 124 logger.Debugf("obtained image datasource %q", ds.Description()) 125 } 126 return sources, nil 127 } 128 129 // environmentDataSources returns simplestreams datasources for the environment 130 // by calling the functions registered in RegisterImageDataSourceFunc. 131 // The datasources returned will be in the same order the functions were registered. 132 func environmentDataSources(bootstrapEnviron BootstrapEnviron) ([]simplestreams.DataSource, error) { 133 datasourceFuncsMu.RLock() 134 defer datasourceFuncsMu.RUnlock() 135 var datasources []simplestreams.DataSource 136 env, ok := bootstrapEnviron.(Environ) 137 if !ok { 138 logger.Debugf("environmentDataSources is supported for IAAS, environ %#v is not Environ", bootstrapEnviron) 139 // ignore for CAAS 140 return datasources, nil 141 } 142 for _, f := range datasourceFuncs { 143 datasource, err := f.f(env) 144 if err != nil { 145 if errors.IsNotSupported(err) { 146 continue 147 } 148 return nil, err 149 } 150 datasources = append(datasources, datasource) 151 } 152 return datasources, nil 153 }