/
doc.go
361 lines (293 loc) · 10.7 KB
/
doc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package mongodoc // import "gopkg.in/juju/charmstore.v5/internal/mongodoc"
import (
"time"
"gopkg.in/errgo.v1"
"gopkg.in/juju/charm.v6"
"gopkg.in/juju/charmrepo.v3/csclient/params"
"gopkg.in/mgo.v2/bson"
)
// Entity holds the in-database representation of charm or bundle's
// document in the charms collection. It holds information
// on one specific revision and series of the charm or bundle - see
// also BaseEntity.
//
// We ensure that there is always a single BaseEntity for any
// set of entities which share the same base URL.
type Entity struct {
// URL holds the fully specified URL of the charm or bundle.
// e.g. cs:precise/wordpress-34, cs:~user/trusty/foo-2
URL *charm.URL `bson:"_id"`
// BaseURL holds the reference URL of the charm or bundle
// (this omits the series and revision from URL)
// e.g. cs:wordpress, cs:~user/foo
BaseURL *charm.URL
// User holds the user part of the entity URL (for instance, "joe").
User string
// Name holds the name of the entity (for instance "wordpress").
Name string
// Revision holds the entity revision (it cannot be -1/unset).
Revision int
// Series holds the entity series (for instance "trusty" or "bundle").
// For multi-series charms, this will be empty.
Series string
// SupportedSeries holds the series supported by a charm.
// For non-multi-series charms, this is a single element slice
// containing the value in Series.
SupportedSeries []string
// PreV5BlobHash holds the hash checksum of the
// blob that will be served from the v4 and legacy
// APIs. This will be the same as BlobHash for single-series charms.
PreV5BlobHash string
// PreV5BlobExtraHash holds the hash of the extra
// blob that's appended to the main blob. This is empty
// when PreV5BlobHash is the same as BlobHash.
PreV5BlobExtraHash string `bson:",omitempty"`
// PreV5BlobSize holds the size of the
// blob that will be served from the v4 and legacy
// APIs. This will be the same as Size for single-series charms.
PreV5BlobSize int64
// PreV5BlobHash256 holds the SHA256 hash checksum
// of the blob that will be served from the v4 and legacy
// APIs. This will be the same as Hash256 for single-series charms.
PreV5BlobHash256 string
// BlobHash holds the hash checksum of the blob, in hexadecimal format,
// as created by blobstore.NewHash.
BlobHash string
// BlobHash256 holds the SHA256 hash checksum of the blob,
// in hexadecimal format. This is only used by the legacy
// API, and is calculated lazily the first time it is required.
// Note that this is calculated from the pre-V5 blob.
BlobHash256 string
// Size holds the size of the archive blob.
// TODO(rog) rename this to BlobSize.
Size int64
UploadTime time.Time
// ExtraInfo holds arbitrary extra metadata associated with
// the entity. The byte slices hold JSON-encoded data.
ExtraInfo map[string][]byte `bson:",omitempty" json:",omitempty"`
// TODO(rog) verify that all these types marshal to the expected
// JSON form.
CharmMeta *charm.Meta
CharmMetrics *charm.Metrics
CharmConfig *charm.Config
CharmActions *charm.Actions
// CharmProvidedInterfaces holds all the relation
// interfaces provided by the charm
CharmProvidedInterfaces []string
// CharmRequiredInterfaces is similar to CharmProvidedInterfaces
// for required interfaces.
CharmRequiredInterfaces []string
BundleData *charm.BundleData
BundleReadMe string
// BundleCharms includes all the charm URLs referenced
// by the bundle, including base URLs where they are
// not already included.
BundleCharms []*charm.URL
// BundleMachineCount counts the machines used or created
// by the bundle. It is nil for charms.
BundleMachineCount *int
// BundleUnitCount counts the units created by the bundle.
// It is nil for charms.
BundleUnitCount *int
// TODO Add fields denormalized for search purposes
// and search ranking field(s).
// Contents holds entries for frequently accessed
// entries in the file's blob. Storing this avoids
// the need to linearly read the zip file's manifest
// every time we access one of these files.
Contents map[FileId]ZipFile `json:",omitempty" bson:",omitempty"`
// PromulgatedURL holds the promulgated URL of the entity. If the entity
// is not promulgated this should be set to nil.
PromulgatedURL *charm.URL `json:",omitempty" bson:"promulgated-url,omitempty"`
// PromulgatedRevision holds the revision number from the promulgated URL.
// If the entity is not promulgated this should be set to -1.
PromulgatedRevision int `bson:"promulgated-revision"`
// Published holds whether the entity has been published on a channel.
Published map[params.Channel]bool `json:",omitempty" bson:",omitempty"`
}
// PreferredURL returns the preferred way to refer to this entity. If
// the entity has a promulgated URL and usePromulgated is true then the
// promulgated URL will be used, otherwise the standard URL is used.
//
// The returned URL may be modified freely.
func (e *Entity) PreferredURL(usePromulgated bool) *charm.URL {
var u charm.URL
if usePromulgated && e.PromulgatedURL != nil {
u = *e.PromulgatedURL
} else {
u = *e.URL
}
return &u
}
// BaseEntity holds metadata for a charm or bundle
// independent of any specific uploaded revision or series.
type BaseEntity struct {
// URL holds the reference URL of of charm on bundle
// regardless of its revision, series or promulgation status
// (this omits the revision and series from URL).
// e.g., cs:~user/collection/foo
URL *charm.URL `bson:"_id"`
// User holds the user part of the entity URL (for instance, "joe").
User string
// Name holds the name of the entity (for instance "wordpress").
Name string
// Promulgated specifies whether the charm or bundle should be
// promulgated.
Promulgated IntBool
// CommonInfo holds arbitrary common extra metadata associated with
// the base entity. Thhose data apply to all revisions.
// The byte slices hold JSON-encoded data.
CommonInfo map[string][]byte `bson:",omitempty" json:",omitempty"`
// ChannelACLs holds a map from an entity channel to the ACLs
// that apply to entities that use this base entity that are associated
// with the given channel.
ChannelACLs map[params.Channel]ACL
// ChannelEntities holds a set of channels, each containing a set
// of series holding the currently published entity revision for
// that channel and series.
ChannelEntities map[params.Channel]map[string]*charm.URL
// ChannelResources holds a set of channels, each containing a
// set of resource names holding the currently published resource
// version for that channel and resource name.
ChannelResources map[params.Channel][]ResourceRevision
// NoIngest is set to true when a charm or bundle has been uploaded
// with a POST request. Since the ingester only uses PUT requests
// at present, this signifies that someone has taken over control from
// the ingester.
NoIngest bool `bson:",omitempty"`
}
// LatestRevision holds an entry in the revisions collection.
type LatestRevision struct {
// URL holds the id that the latest revision is associated
// with. URL.Revision is always -1.
URL *charm.URL `bson:"_id"`
// BaseURL holds the reference URL of the charm or bundle
// (this omits the series from URL)
// e.g. cs:wordpress, cs:~user/foo
BaseURL *charm.URL
// Revision holds the latest known revision for the
// URL.
Revision int
}
// ResourceRevision specifies an association of a resource name to a
// revision.
type ResourceRevision struct {
Name string
Revision int
}
// ACL holds lists of users and groups that are
// allowed to perform specific actions.
type ACL struct {
// Read holds users and groups that are allowed to read the charm
// or bundle.
Read []string
// Write holds users and groups that are allowed to upload/modify the charm
// or bundle.
Write []string
}
type FileId string
const (
FileReadMe FileId = "readme"
FileIcon FileId = "icon"
)
// ZipFile refers to a specific file in the uploaded archive blob.
type ZipFile struct {
// Compressed specifies whether the file is compressed or not.
Compressed bool
// Offset holds the offset into the zip archive of the start of
// the file's data.
Offset int64
// Size holds the size of the file before decompression.
Size int64
}
// Valid reports whether f is a valid (non-zero) reference to
// a zip file.
func (f ZipFile) IsValid() bool {
// Note that no valid zip files can start at offset zero,
// because that's where the zip header lives.
return f != ZipFile{}
}
// Log holds the in-database representation of a log message sent to the charm
// store.
type Log struct {
// Data holds the JSON-encoded log message.
Data []byte
// Level holds the log level: whether the log is a warning, an error, etc.
Level LogLevel
// Type holds the log type.
Type LogType
// URLs holds a slice of entity URLs associated with the log message.
URLs []*charm.URL
// Time holds the time of the log.
Time time.Time
}
// LogLevel holds the level associated with a log.
type LogLevel int
// When introducing a new log level, do the following:
// 1) add the new level as a constant below;
// 2) add the new level in params as a string for HTTP requests/responses;
// 3) include the new level in the mongodocLogLevels and paramsLogLevels maps
// in internal/v4.
const (
_ LogLevel = iota
InfoLevel
WarningLevel
ErrorLevel
)
// LogType holds the type of the log.
type LogType int
// When introducing a new log type, do the following:
// 1) add the new type as a constant below;
// 2) add the new type in params as a string for HTTP requests/responses;
// 3) include the new type in the mongodocLogTypes and paramsLogTypes maps
// in internal/v4.
const (
_ LogType = iota
IngestionType
LegacyStatisticsType
)
type MigrationName string
// Migration holds information about the database migration.
type Migration struct {
// Executed holds the migration names for migrations already executed.
Executed []MigrationName
}
// IntBool is a bool that will be represented internally in the database as 1 for
// true and -1 for false.
type IntBool bool
func (b IntBool) GetBSON() (interface{}, error) {
if b {
return 1, nil
}
return -1, nil
}
func (b *IntBool) SetBSON(raw bson.Raw) error {
var x int
if err := raw.Unmarshal(&x); err != nil {
return errgo.Notef(err, "cannot unmarshal value")
}
switch x {
case 1:
*b = IntBool(true)
case -1:
*b = IntBool(false)
default:
return errgo.Newf("invalid value %d", x)
}
return nil
}
// BaseURL returns the "base" version of url. If
// url represents an entity, then the returned URL
// will represent its base entity.
func BaseURL(url *charm.URL) *charm.URL {
newURL := *url
newURL.Revision = -1
newURL.Series = ""
return &newURL
}
func copyURL(u *charm.URL) *charm.URL {
u1 := *u
return &u1
}