github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "github.com/juju/utils" 11 12 "github.com/juju/juju/environs/imagemetadata" 13 "github.com/juju/juju/environs/simplestreams" 14 ) 15 16 type datasourceFuncId struct { 17 id string 18 f ImageDataSourceFunc 19 } 20 21 var ( 22 datasourceFuncsMu sync.RWMutex 23 datasourceFuncs []datasourceFuncId 24 ) 25 26 // ImageDataSourceFunc is a function type that takes an environment and 27 // returns a simplestreams datasource. 28 // 29 // ImageDataSourceFunc will be used in ImageMetadataSources. 30 // Any error satisfying errors.IsNotSupported will be ignored; 31 // any other error will be cause ImageMetadataSources to fail. 32 type ImageDataSourceFunc func(Environ) (simplestreams.DataSource, error) 33 34 // RegisterUserImageDataSourceFunc registers an ImageDataSourceFunc 35 // with the specified id at the start of the search path, overwriting 36 // any function previously registered with the same id. 37 func RegisterUserImageDataSourceFunc(id string, f ImageDataSourceFunc) { 38 datasourceFuncsMu.Lock() 39 defer datasourceFuncsMu.Unlock() 40 for i := range datasourceFuncs { 41 if datasourceFuncs[i].id == id { 42 datasourceFuncs[i].f = f 43 return 44 } 45 } 46 logger.Debugf("new user image datasource registered: %v", id) 47 datasourceFuncs = append([]datasourceFuncId{datasourceFuncId{id, f}}, datasourceFuncs...) 48 } 49 50 // RegisterImageDataSourceFunc registers an ImageDataSourceFunc 51 // with the specified id, overwriting any function previously registered 52 // with the same id. 53 func RegisterImageDataSourceFunc(id string, f ImageDataSourceFunc) { 54 datasourceFuncsMu.Lock() 55 defer datasourceFuncsMu.Unlock() 56 for i := range datasourceFuncs { 57 if datasourceFuncs[i].id == id { 58 datasourceFuncs[i].f = f 59 return 60 } 61 } 62 logger.Debugf("new model image datasource registered: %v", id) 63 datasourceFuncs = append(datasourceFuncs, datasourceFuncId{id, f}) 64 } 65 66 // UnregisterImageDataSourceFunc unregisters an ImageDataSourceFunc 67 // with the specified id. 68 func UnregisterImageDataSourceFunc(id string) { 69 datasourceFuncsMu.Lock() 70 defer datasourceFuncsMu.Unlock() 71 for i, f := range datasourceFuncs { 72 if f.id == id { 73 head := datasourceFuncs[:i] 74 tail := datasourceFuncs[i+1:] 75 datasourceFuncs = append(head, tail...) 76 return 77 } 78 } 79 } 80 81 // ImageMetadataSources returns the sources to use when looking for 82 // simplestreams image id metadata for the given stream. 83 func ImageMetadataSources(env Environ) ([]simplestreams.DataSource, error) { 84 config := env.Config() 85 86 // Add configured and environment-specific datasources. 87 var sources []simplestreams.DataSource 88 if userURL, ok := config.ImageMetadataURL(); ok { 89 verify := utils.VerifySSLHostnames 90 if !config.SSLHostnameVerification() { 91 verify = utils.NoVerifySSLHostnames 92 } 93 publicKey, _ := simplestreams.UserPublicSigningKey() 94 sources = append(sources, simplestreams.NewURLSignedDataSource("image-metadata-url", userURL, publicKey, verify, simplestreams.SPECIFIC_CLOUD_DATA, false)) 95 } 96 97 envDataSources, err := environmentDataSources(env) 98 if err != nil { 99 return nil, err 100 } 101 sources = append(sources, envDataSources...) 102 103 // Add the official image metadata datasources. 104 officialDataSources, err := imagemetadata.OfficialDataSources(config.ImageStream()) 105 if err != nil { 106 return nil, err 107 } 108 for _, source := range officialDataSources { 109 sources = append(sources, source) 110 } 111 for _, ds := range sources { 112 logger.Debugf("obtained image datasource %q", ds.Description()) 113 } 114 return sources, nil 115 } 116 117 // environmentDataSources returns simplestreams datasources for the environment 118 // by calling the functions registered in RegisterImageDataSourceFunc. 119 // The datasources returned will be in the same order the functions were registered. 120 func environmentDataSources(env Environ) ([]simplestreams.DataSource, error) { 121 datasourceFuncsMu.RLock() 122 defer datasourceFuncsMu.RUnlock() 123 var datasources []simplestreams.DataSource 124 for _, f := range datasourceFuncs { 125 datasource, err := f.f(env) 126 if err != nil { 127 if errors.IsNotSupported(err) { 128 continue 129 } 130 return nil, err 131 } 132 datasources = append(datasources, datasource) 133 } 134 return datasources, nil 135 }