OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package cipd | 5 package cipd |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "encoding/json" | 9 "encoding/json" |
10 "errors" | 10 "errors" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 Info packageInstanceInfo | 60 Info packageInstanceInfo |
61 } | 61 } |
62 | 62 |
63 // roleChangeMsg corresponds to RoleChange proto message on backend. | 63 // roleChangeMsg corresponds to RoleChange proto message on backend. |
64 type roleChangeMsg struct { | 64 type roleChangeMsg struct { |
65 Action string `json:"action"` | 65 Action string `json:"action"` |
66 Role string `json:"role"` | 66 Role string `json:"role"` |
67 Principal string `json:"principal"` | 67 Principal string `json:"principal"` |
68 } | 68 } |
69 | 69 |
| 70 // pendingProcessingError is returned by attachTags if package instance is not |
| 71 // yet ready and the call should be retried later. |
| 72 type pendingProcessingError struct { |
| 73 message string |
| 74 } |
| 75 |
| 76 func (e *pendingProcessingError) Error() string { |
| 77 return e.message |
| 78 } |
| 79 |
70 // newRemoteService is mocked in tests. | 80 // newRemoteService is mocked in tests. |
71 var newRemoteService = func(client *http.Client, url string, log logging.Logger)
*remoteService { | 81 var newRemoteService = func(client *http.Client, url string, log logging.Logger)
*remoteService { |
72 log.Infof("cipd: service URL is %s", url) | 82 log.Infof("cipd: service URL is %s", url) |
73 return &remoteService{ | 83 return &remoteService{ |
74 client: client, | 84 client: client, |
75 serviceURL: url, | 85 serviceURL: url, |
76 log: log, | 86 log: log, |
77 } | 87 } |
78 } | 88 } |
79 | 89 |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 } | 342 } |
333 switch reply.Status { | 343 switch reply.Status { |
334 case "SUCCESS": | 344 case "SUCCESS": |
335 return nil | 345 return nil |
336 case "ERROR": | 346 case "ERROR": |
337 return errors.New(reply.ErrorMessage) | 347 return errors.New(reply.ErrorMessage) |
338 } | 348 } |
339 return fmt.Errorf("Unexpected reply status: %s", reply.Status) | 349 return fmt.Errorf("Unexpected reply status: %s", reply.Status) |
340 } | 350 } |
341 | 351 |
| 352 func (r *remoteService) attachTags(packageName, instanceID string, tags []string
) error { |
| 353 // Tags will be passed in the request body, not via URL. |
| 354 endpoint, err := tagsEndpoint(packageName, instanceID, nil) |
| 355 if err != nil { |
| 356 return err |
| 357 } |
| 358 |
| 359 if len(tags) == 0 { |
| 360 return errors.New("At least one tag must be provided") |
| 361 } |
| 362 for _, tag := range tags { |
| 363 err = ValidateInstanceTag(tag) |
| 364 if err != nil { |
| 365 return err |
| 366 } |
| 367 } |
| 368 var request struct { |
| 369 Tags []string `json:"tags"` |
| 370 } |
| 371 request.Tags = tags |
| 372 |
| 373 var reply struct { |
| 374 Status string `json:"status"` |
| 375 ErrorMessage string `json:"error_message"` |
| 376 } |
| 377 err = r.makeRequest(endpoint, "POST", &request, &reply) |
| 378 if err != nil { |
| 379 return err |
| 380 } |
| 381 switch reply.Status { |
| 382 case "SUCCESS": |
| 383 return nil |
| 384 case "PROCESSING_NOT_FINISHED_YET": |
| 385 return &pendingProcessingError{reply.ErrorMessage} |
| 386 case "ERROR", "PROCESSING_FAILED": |
| 387 return errors.New(reply.ErrorMessage) |
| 388 } |
| 389 return fmt.Errorf("Unexpected status when attaching tags: %s", reply.Sta
tus) |
| 390 } |
| 391 |
342 //////////////////////////////////////////////////////////////////////////////// | 392 //////////////////////////////////////////////////////////////////////////////// |
343 | 393 |
344 func instanceEndpoint(packageName, instanceID string) (string, error) { | 394 func instanceEndpoint(packageName, instanceID string) (string, error) { |
345 err := ValidatePackageName(packageName) | 395 err := ValidatePackageName(packageName) |
346 if err != nil { | 396 if err != nil { |
347 return "", err | 397 return "", err |
348 } | 398 } |
349 err = ValidateInstanceID(instanceID) | 399 err = ValidateInstanceID(instanceID) |
350 if err != nil { | 400 if err != nil { |
351 return "", err | 401 return "", err |
352 } | 402 } |
353 params := url.Values{} | 403 params := url.Values{} |
354 params.Add("package_name", packageName) | 404 params.Add("package_name", packageName) |
355 params.Add("instance_id", instanceID) | 405 params.Add("instance_id", instanceID) |
356 return "repo/v1/instance?" + params.Encode(), nil | 406 return "repo/v1/instance?" + params.Encode(), nil |
357 } | 407 } |
358 | 408 |
359 func aclEndpoint(packagePath string) (string, error) { | 409 func aclEndpoint(packagePath string) (string, error) { |
360 err := ValidatePackageName(packagePath) | 410 err := ValidatePackageName(packagePath) |
361 if err != nil { | 411 if err != nil { |
362 return "", err | 412 return "", err |
363 } | 413 } |
364 params := url.Values{} | 414 params := url.Values{} |
365 params.Add("package_path", packagePath) | 415 params.Add("package_path", packagePath) |
366 return "repo/v1/acl?" + params.Encode(), nil | 416 return "repo/v1/acl?" + params.Encode(), nil |
367 } | 417 } |
368 | 418 |
| 419 func tagsEndpoint(packageName, instanceID string, tags []string) (string, error)
{ |
| 420 err := ValidatePackageName(packageName) |
| 421 if err != nil { |
| 422 return "", err |
| 423 } |
| 424 err = ValidateInstanceID(instanceID) |
| 425 if err != nil { |
| 426 return "", err |
| 427 } |
| 428 for _, tag := range tags { |
| 429 err = ValidateInstanceTag(tag) |
| 430 if err != nil { |
| 431 return "", err |
| 432 } |
| 433 } |
| 434 params := url.Values{} |
| 435 params.Add("package_name", packageName) |
| 436 params.Add("instance_id", instanceID) |
| 437 for _, tag := range tags { |
| 438 params.Add("tag", tag) |
| 439 } |
| 440 return "repo/v1/tags?" + params.Encode(), nil |
| 441 } |
| 442 |
369 // convertTimestamp coverts string with int64 timestamp in microseconds since | 443 // convertTimestamp coverts string with int64 timestamp in microseconds since |
370 // to time.Time | 444 // to time.Time |
371 func convertTimestamp(ts string) (time.Time, error) { | 445 func convertTimestamp(ts string) (time.Time, error) { |
372 i, err := strconv.ParseInt(ts, 10, 64) | 446 i, err := strconv.ParseInt(ts, 10, 64) |
373 if err != nil { | 447 if err != nil { |
374 return time.Time{}, fmt.Errorf("Unexpected timestamp value '%s'
in the server response", ts) | 448 return time.Time{}, fmt.Errorf("Unexpected timestamp value '%s'
in the server response", ts) |
375 } | 449 } |
376 return time.Unix(0, i*1000), nil | 450 return time.Unix(0, i*1000), nil |
377 } | 451 } |
378 | 452 |
379 func makePackageInstanceInfo(msg packageInstanceMsg) (pi packageInstanceInfo, er
r error) { | 453 func makePackageInstanceInfo(msg packageInstanceMsg) (pi packageInstanceInfo, er
r error) { |
380 ts, err := convertTimestamp(msg.RegisteredTs) | 454 ts, err := convertTimestamp(msg.RegisteredTs) |
381 if err != nil { | 455 if err != nil { |
382 return | 456 return |
383 } | 457 } |
384 pi = packageInstanceInfo{ | 458 pi = packageInstanceInfo{ |
385 PackageName: msg.PackageName, | 459 PackageName: msg.PackageName, |
386 InstanceID: msg.InstanceID, | 460 InstanceID: msg.InstanceID, |
387 RegisteredBy: msg.RegisteredBy, | 461 RegisteredBy: msg.RegisteredBy, |
388 RegisteredTs: ts, | 462 RegisteredTs: ts, |
389 } | 463 } |
390 return | 464 return |
391 } | 465 } |
OLD | NEW |