github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/environs/tools/urls.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package tools 5 6 import ( 7 "sync" 8 9 "github.com/juju/errors" 10 "github.com/juju/utils" 11 12 "github.com/juju/juju/environs" 13 conf "github.com/juju/juju/environs/config" 14 "github.com/juju/juju/environs/simplestreams" 15 "github.com/juju/juju/environs/storage" 16 envutils "github.com/juju/juju/environs/utils" 17 ) 18 19 type toolsDatasourceFuncId struct { 20 id string 21 f ToolsDataSourceFunc 22 } 23 24 var ( 25 toolsDatasourceFuncsMu sync.RWMutex 26 toolsDatasourceFuncs []toolsDatasourceFuncId 27 ) 28 29 // ToolsDataSourceFunc is a function type that takes an environment and 30 // returns a simplestreams datasource. 31 // 32 // ToolsDataSourceFunc will be used in GetMetadataSources. 33 // Any error satisfying errors.IsNotSupported will be ignored; 34 // any other error will be cause GetMetadataSources to fail. 35 type ToolsDataSourceFunc func(environs.Environ) (simplestreams.DataSource, error) 36 37 // RegisterToolsDataSourceFunc registers an ToolsDataSourceFunc 38 // with the specified id, overwriting any function previously registered 39 // with the same id. 40 func RegisterToolsDataSourceFunc(id string, f ToolsDataSourceFunc) { 41 toolsDatasourceFuncsMu.Lock() 42 defer toolsDatasourceFuncsMu.Unlock() 43 for i := range toolsDatasourceFuncs { 44 if toolsDatasourceFuncs[i].id == id { 45 toolsDatasourceFuncs[i].f = f 46 return 47 } 48 } 49 toolsDatasourceFuncs = append(toolsDatasourceFuncs, toolsDatasourceFuncId{id, f}) 50 } 51 52 // UnregisterToolsDataSourceFunc unregisters an ToolsDataSourceFunc 53 // with the specified id. 54 func UnregisterToolsDataSourceFunc(id string) { 55 toolsDatasourceFuncsMu.Lock() 56 defer toolsDatasourceFuncsMu.Unlock() 57 for i, f := range toolsDatasourceFuncs { 58 if f.id == id { 59 head := toolsDatasourceFuncs[:i] 60 tail := toolsDatasourceFuncs[i+1:] 61 toolsDatasourceFuncs = append(head, tail...) 62 return 63 } 64 } 65 } 66 67 // GetMetadataSources returns the sources to use when looking for 68 // simplestreams tools metadata for the given stream. 69 func GetMetadataSources(env environs.Environ) ([]simplestreams.DataSource, error) { 70 config := env.Config() 71 72 // Add configured and environment-specific datasources. 73 var sources []simplestreams.DataSource 74 if userURL, ok := config.AgentMetadataURL(); ok { 75 verify := utils.VerifySSLHostnames 76 if !config.SSLHostnameVerification() { 77 verify = utils.NoVerifySSLHostnames 78 } 79 sources = append(sources, simplestreams.NewURLDataSource(conf.AgentMetadataURLKey, userURL, verify)) 80 } 81 82 envDataSources, err := environmentDataSources(env) 83 if err != nil { 84 return nil, err 85 } 86 sources = append(sources, envDataSources...) 87 88 // Add the default, public datasource. 89 defaultURL, err := ToolsURL(DefaultBaseURL) 90 if err != nil { 91 return nil, err 92 } 93 if defaultURL != "" { 94 sources = append(sources, 95 simplestreams.NewURLDataSource("default simplestreams", defaultURL, utils.VerifySSLHostnames)) 96 } 97 return sources, nil 98 } 99 100 // environmentDataSources returns simplestreams datasources for the environment 101 // by calling the functions registered in RegisterToolsDataSourceFunc. 102 // The datasources returned will be in the same order the functions were registered. 103 func environmentDataSources(env environs.Environ) ([]simplestreams.DataSource, error) { 104 toolsDatasourceFuncsMu.RLock() 105 defer toolsDatasourceFuncsMu.RUnlock() 106 var datasources []simplestreams.DataSource 107 for _, f := range toolsDatasourceFuncs { 108 logger.Debugf("trying datasource %q", f.id) 109 datasource, err := f.f(env) 110 if err != nil { 111 if errors.IsNotSupported(err) { 112 continue 113 } 114 return nil, err 115 } 116 datasources = append(datasources, datasource) 117 } 118 return datasources, nil 119 } 120 121 // ToolsURL returns a valid tools URL constructed from source. 122 // source may be a directory, or a URL like file://foo or http://foo. 123 func ToolsURL(source string) (string, error) { 124 if source == "" { 125 return "", nil 126 } 127 128 return envutils.GetURL(source, storage.BaseToolsPath) 129 }