github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/common/tools.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "fmt" 8 9 "launchpad.net/juju-core/environs" 10 "launchpad.net/juju-core/environs/config" 11 envtools "launchpad.net/juju-core/environs/tools" 12 "launchpad.net/juju-core/state" 13 "launchpad.net/juju-core/state/api/params" 14 coretools "launchpad.net/juju-core/tools" 15 "launchpad.net/juju-core/version" 16 ) 17 18 type EntityFinderEnvironConfigGetter interface { 19 state.EntityFinder 20 EnvironConfig() (*config.Config, error) 21 } 22 23 // ToolsGetter implements a common Tools method for use by various 24 // facades. 25 type ToolsGetter struct { 26 st EntityFinderEnvironConfigGetter 27 getCanRead GetAuthFunc 28 } 29 30 // NewToolsGetter returns a new ToolsGetter. The GetAuthFunc will be 31 // used on each invocation of Tools to determine current permissions. 32 func NewToolsGetter(st EntityFinderEnvironConfigGetter, getCanRead GetAuthFunc) *ToolsGetter { 33 return &ToolsGetter{ 34 st: st, 35 getCanRead: getCanRead, 36 } 37 } 38 39 // Tools finds the tools necessary for the given agents. 40 func (t *ToolsGetter) Tools(args params.Entities) (params.ToolsResults, error) { 41 result := params.ToolsResults{ 42 Results: make([]params.ToolsResult, len(args.Entities)), 43 } 44 canRead, err := t.getCanRead() 45 if err != nil { 46 return result, err 47 } 48 agentVersion, cfg, err := t.getGlobalAgentVersion() 49 if err != nil { 50 return result, err 51 } 52 // SSLHostnameVerification defaults to true, so we need to 53 // invert that, for backwards-compatibility (older versions 54 // will have DisableSSLHostnameVerification: false by default). 55 disableSSLHostnameVerification := !cfg.SSLHostnameVerification() 56 env, err := environs.New(cfg) 57 if err != nil { 58 return result, err 59 } 60 for i, entity := range args.Entities { 61 agentTools, err := t.oneAgentTools(canRead, entity.Tag, agentVersion, env) 62 if err == nil { 63 result.Results[i].Tools = agentTools 64 result.Results[i].DisableSSLHostnameVerification = disableSSLHostnameVerification 65 } 66 result.Results[i].Error = ServerError(err) 67 } 68 return result, nil 69 } 70 71 func (t *ToolsGetter) getGlobalAgentVersion() (version.Number, *config.Config, error) { 72 // Get the Agent Version requested in the Environment Config 73 nothing := version.Number{} 74 cfg, err := t.st.EnvironConfig() 75 if err != nil { 76 return nothing, nil, err 77 } 78 agentVersion, ok := cfg.AgentVersion() 79 if !ok { 80 return nothing, nil, fmt.Errorf("agent version not set in environment config") 81 } 82 return agentVersion, cfg, nil 83 } 84 85 func (t *ToolsGetter) oneAgentTools(canRead AuthFunc, tag string, agentVersion version.Number, env environs.Environ) (*coretools.Tools, error) { 86 if !canRead(tag) { 87 return nil, ErrPerm 88 } 89 entity, err := t.st.FindEntity(tag) 90 if err != nil { 91 return nil, err 92 } 93 tooler, ok := entity.(state.AgentTooler) 94 if !ok { 95 return nil, NotSupportedError(tag, "agent tools") 96 } 97 existingTools, err := tooler.AgentTools() 98 if err != nil { 99 return nil, err 100 } 101 // TODO(jam): Avoid searching the provider for every machine 102 // that wants to upgrade. The information could just be cached 103 // in state, or even in the API servers 104 return envtools.FindExactTools(env, agentVersion, existingTools.Version.Series, existingTools.Version.Arch) 105 } 106 107 // ToolsSetter implements a common Tools method for use by various 108 // facades. 109 type ToolsSetter struct { 110 st state.EntityFinder 111 getCanWrite GetAuthFunc 112 } 113 114 // NewToolsGetter returns a new ToolsGetter. The GetAuthFunc will be 115 // used on each invocation of Tools to determine current permissions. 116 func NewToolsSetter(st state.EntityFinder, getCanWrite GetAuthFunc) *ToolsSetter { 117 return &ToolsSetter{ 118 st: st, 119 getCanWrite: getCanWrite, 120 } 121 } 122 123 // SetTools updates the recorded tools version for the agents. 124 func (t *ToolsSetter) SetTools(args params.EntitiesVersion) (params.ErrorResults, error) { 125 results := params.ErrorResults{ 126 Results: make([]params.ErrorResult, len(args.AgentTools)), 127 } 128 canWrite, err := t.getCanWrite() 129 if err != nil { 130 return results, err 131 } 132 for i, agentTools := range args.AgentTools { 133 err := t.setOneAgentVersion(agentTools.Tag, agentTools.Tools.Version, canWrite) 134 results.Results[i].Error = ServerError(err) 135 } 136 return results, nil 137 } 138 139 func (t *ToolsSetter) setOneAgentVersion(tag string, vers version.Binary, canWrite AuthFunc) error { 140 if !canWrite(tag) { 141 return ErrPerm 142 } 143 entity0, err := t.st.FindEntity(tag) 144 if err != nil { 145 return err 146 } 147 entity, ok := entity0.(state.AgentTooler) 148 if !ok { 149 return NotSupportedError(tag, "agent tools") 150 } 151 return entity.SetAgentVersion(vers) 152 }