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