Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: milo/appengine/common/config.go

Issue 2801463002: Milo: Use custom config caching layer (Closed)
Patch Set: Working Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The LUCI Authors. All rights reserved. 1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package common 5 package common
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "time"
9 10
10 "github.com/luci/gae/service/datastore" 11 "github.com/luci/gae/service/datastore"
11 "github.com/luci/gae/service/info" 12 "github.com/luci/gae/service/info"
12 "github.com/luci/luci-go/common/logging" 13 "github.com/luci/luci-go/common/logging"
13 "github.com/luci/luci-go/luci_config/server/cfgclient" 14 "github.com/luci/luci-go/luci_config/server/cfgclient"
14 "github.com/luci/luci-go/luci_config/server/cfgclient/textproto" 15 "github.com/luci/luci-go/luci_config/server/cfgclient/textproto"
15 "github.com/luci/luci-go/milo/common/config" 16 "github.com/luci/luci-go/milo/common/config"
16 17
17 "github.com/golang/protobuf/proto" 18 "github.com/golang/protobuf/proto"
18 "golang.org/x/net/context" 19 "golang.org/x/net/context"
19 ) 20 )
20 21
21 // Project is a LUCI project. 22 // Project is a LUCI project.
22 type Project struct { 23 type Project struct {
23 // The ID of the project, as per self defined. This is not the luci-cfg 24 // The ID of the project, as per self defined. This is not the luci-cfg
24 // name. 25 // name.
25 ID string `gae:"$id"` 26 ID string `gae:"$id"`
26 // The luci-cfg name of the project. 27 // The luci-cfg name of the project.
27 Name string 28 Name string
28 // The Project data in protobuf binary format. 29 // The Project data in protobuf binary format.
29 Data []byte `gae:",noindex"` 30 Data []byte `gae:",noindex"`
30 } 31 }
31 32
33 // The key for the service config entity in datastore.
34 const ID = "service_config"
nodir 2017/04/04 23:12:08 this looks as common.ID for other packages, which
hinoka 2017/04/05 20:45:06 Done.
35
36 // ServiceConfig is a container for the instance's service config.
37 type ServiceConfig struct {
38 // ID is the datastore key. This should be static, as there should only be
39 // one service config.
40 ID string `gae:"$id"`
41 // Revision is the revision of the config, taken from luci-config. This is used
42 // to determine if the entry needs to be refreshed.
43 Revision string
44 // Data The binary proto of the config.
nodir 2017/04/04 23:12:08 s/The/is the/ ?
hinoka 2017/04/05 20:45:06 Done.
45 Data []byte `gae:",noindex"`
46 // Text is the text format of the config. For human consumption only.
47 Text string `gae:",noindex"`
48 // LastUpdated is the time this config was last updated.
49 LastUpdated time.Time
50 }
51
32 // GetServiceConfig returns the service (aka global) config for the current 52 // GetServiceConfig returns the service (aka global) config for the current
33 // instance of Milo. 53 // instance of Milo from the datastore. Returns an empty config and warn heavil y
34 func GetSettings(c context.Context) (*config.Settings, error) { 54 // if none is found.
35 » cs := cfgclient.CurrentServiceConfigSet(c) 55 // TODO(hinoka): Use process cache to cache configs.
36 » msg := &config.Settings{} 56 func GetSettings(c context.Context) *config.Settings {
37 » // Our global config name is called settings.cfg. 57 » settings := config.Settings{
38 » err := cfgclient.Get(c, cfgclient.AsService, cs, "settings.cfg", textpro to.Message(msg), nil) 58 » » Buildbot: &config.Settings_Buildbot{},
39 » switch err { 59 » }
40 » case cfgclient.ErrNoConfig: 60
41 » » // Just warn very heavily in the logs, but don't 500, instead re turn an 61 » msg, err := GetCurrentServiceConfig(c)
42 » » // empty config. 62 » if err != nil {
43 » » logging.WithError(err).Errorf(c, "settings.cfg does not exist") 63 » » // The service config does not exist, just return an empty confi g
44 » » msg.Buildbot = &config.Settings_Buildbot{} 64 » » // and complain loudly in the logs.
45 » » err = nil 65 » » logging.WithError(err).Errorf(c,
46 » case nil: 66 » » » "Encountered error while loading service config, using e mpty config.")
47 » » // continue 67 » » return &settings
48 » default: 68 » }
69
70 » err = proto.Unmarshal(msg.Data, &settings)
71 » if err != nil {
72 » » // The service config does not exist, just return an empty confi g
nodir 2017/04/04 23:12:08 i think it does exist, but it is broken
hinoka 2017/04/05 20:45:06 Done.
73 » » // and complain loudly in the logs.
74 » » logging.WithError(err).Errorf(c,
75 » » » "Encountered error while unmarshalling service config, u sing empty config.")
76 » » // Zero out the message just incase something got written in.
77 » » settings.Buildbot = &config.Settings_Buildbot{}
78 » » settings.Buildbucket = nil
79 » » settings.Swarming = nil
nodir 2017/04/04 23:12:08 what if you add more fields there later? it is saf
hinoka 2017/04/05 20:45:06 Done.
80 » }
81
82 » return &settings
83 }
84
85 // GetTextSettings gets
86 func GetCurrentServiceConfig(c context.Context) (*ServiceConfig, error) {
87 » msg := ServiceConfig{ID: ID}
88 » err := datastore.Get(c, &msg)
89 » if err != nil {
49 return nil, err 90 return nil, err
50 } 91 }
51 » return msg, err 92 » logging.Infof(c, "Loaded config entry from %s", msg.LastUpdated.Format(t ime.RFC3339))
nodir 2017/04/04 23:12:08 this functions is going to be used a lot, sometime
hinoka 2017/04/05 20:45:06 Done.
93 » return &msg, nil
94 }
95
96 // UpdateServiceConfig fetches the service config from luci-cfg
nodir 2017/04/04 23:12:08 sometimes this to refers to luci-config as luci-co
nodir 2017/04/04 23:27:15 i meant let's converge on luci-config (not luci-cf
hinoka 2017/04/05 20:45:06 Done.
97 // and then stores the binary proto in datastore.
nodir 2017/04/04 23:12:08 remove "binary" because it is not only binary?
hinoka 2017/04/05 20:45:06 Done.
98 func UpdateServiceConfig(c context.Context) error {
99 » msg := ServiceConfig{ID: ID}
100 » err := datastore.Get(c, &msg)
101 » switch err {
102 » case datastore.ErrNoSuchEntity:
103 » » // Might be the first time this has run.
104 » » logging.WithError(err).Warningf(c, "No existing service config." )
105 » case nil:
106 » » // Continue
107 » default:
108 » » logging.WithError(err).Errorf(c, "Could not load existing config ")
nodir 2017/04/04 23:12:08 general Go suggestion: handle an error only once.
hinoka 2017/04/05 20:45:06 Ok i'll just wrap it.
109 » » return err
110 » }
111
112 » logging.Infof(c, "Loaded config entry (%s) from %s", msg.Revision,
113 » » msg.LastUpdated.Format(time.RFC3339))
114
115 » // Now, load the settings from luci-config.
116 » cs := cfgclient.CurrentServiceConfigSet(c)
nodir 2017/04/04 23:12:08 cfgclient is a wrapper around https://godoc.org/gi
hinoka 2017/04/05 20:45:06 Ah ok. I didn't know that existed, I like that be
117 » settings := &config.Settings{}
118 » meta := &cfgclient.Meta{}
119 » // Our global config name is called settings.cfg.
120 » err = cfgclient.Get(
121 » » c, cfgclient.AsService, cs, "settings.cfg", textproto.Message(se ttings), meta)
122 » if err != nil {
123 » » logging.WithError(err).Errorf(c, "could not load settings.cfg fr om luci-cfg")
124 » » return err
125 » }
126
127 » // Check to see if we need to update
128 » if msg.Revision != "" && msg.Revision == meta.Revision {
nodir 2017/04/04 23:12:08 comparison and put must happen in the same transac
nodir 2017/04/04 23:12:08 != "" seems unnecessary. The revision returned by
hinoka 2017/04/05 20:45:06 Done.
129 » » logging.Infof(c, "revisions matched (%s), no need to update", ms g.Revision)
130 » » return nil
131 » }
132
133 » // We do need to update.
134 » msg.Text = proto.MarshalTextString(settings)
135 » msg.Data, err = proto.Marshal(settings)
136 » if err != nil {
137 » » logging.Errorf(c, "could not marshal proto into binary\n%s", msg .Text)
138 » » return err
139 » }
140 » msg.Revision = meta.Revision
141 » msg.LastUpdated = time.Now().UTC()
nodir 2017/04/04 23:12:08 logging the fact that revisions do not match is mo
hinoka 2017/04/05 20:45:06 Done.
142 » return datastore.Put(c, &msg)
52 } 143 }
53 144
54 // UpdateProjectConfigs internal project configuration based off luci-cfg. 145 // UpdateProjectConfigs internal project configuration based off luci-cfg.
55 // update updates Milo's configuration based off luci config. This includes 146 // update updates Milo's configuration based off luci config. This includes
56 // scanning through all project and extract all console configs. 147 // scanning through all project and extract all console configs.
57 func UpdateProjectConfigs(c context.Context) error { 148 func UpdateProjectConfigs(c context.Context) error {
58 cfgName := info.AppID(c) + ".cfg" 149 cfgName := info.AppID(c) + ".cfg"
59 150
60 var ( 151 var (
61 configs []*config.Project 152 configs []*config.Project
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 if err != nil { 245 if err != nil {
155 return nil, err 246 return nil, err
156 } 247 }
157 for _, cs := range p.Consoles { 248 for _, cs := range p.Consoles {
158 if cs.Name == consoleName { 249 if cs.Name == consoleName {
159 return cs, nil 250 return cs, nil
160 } 251 }
161 } 252 }
162 return nil, fmt.Errorf("Console %s not found in project %s", consoleName , projName) 253 return nil, fmt.Errorf("Console %s not found in project %s", consoleName , projName)
163 } 254 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698