Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 2.6 Into Develop #10367

Merged
merged 29 commits into from
Jun 22, 2019
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fb3ded8
Tie the watcher lifecycle to the catacomb
SimonRichardson Jun 18, 2019
f60a226
Merge pull request #10341 from SimonRichardson/1833155-watcher-leak
jujubot Jun 19, 2019
bc4821b
Improve error checks to cater for 'not found' provider errors that do…
anastasiamac Jun 20, 2019
93a5dbe
add provider level IsNotFound-equivalent methods to providers that ar…
anastasiamac Jun 20, 2019
3d6378c
add provider level IsNotFound-equivalent methods to providers that ar…
anastasiamac Jun 20, 2019
0b44fac
Rename commit command to branch. Enhance renamed branch command to
hmlanigan Jun 18, 2019
9d0975f
Add Created, CreatedBy, and CompletedBy to a Branch in the model cache,
hmlanigan Jun 20, 2019
12d2082
Merge pull request #10359 from hmlanigan/createdtomodelcache
jujubot Jun 20, 2019
208f334
Merge pull request #10346 from hmlanigan/branch
jujubot Jun 20, 2019
4023a75
diversify handling of operational compute errors.
anastasiamac Jun 20, 2019
b1d584c
Use waiterror.
anastasiamac Jun 20, 2019
9a1a7a2
Only inspect errors after all attempts to run an operation have been …
anastasiamac Jun 20, 2019
ef3098c
adjust tests
anastasiamac Jun 21, 2019
16155dd
adjust tests
anastasiamac Jun 21, 2019
25ab285
Merge pull request #10354 from anastasiamac/provider-not-found-errors-25
jujubot Jun 21, 2019
5fd7824
Merge branch '2.5' into merge-25-26-2106
anastasiamac Jun 21, 2019
501494a
Merge branch '2.5' into merge-25-26-2106
anastasiamac Jun 21, 2019
a6d900b
Merge pull request #10362 from anastasiamac/merge-25-26-2106
jujubot Jun 21, 2019
c2391c8
Fixes case where watcher for unit not tracking any branch starts trac…
manadart Jun 21, 2019
56d6c10
Merge pull request #10364 from manadart/2.6-config-watch-branch-deter…
jujubot Jun 21, 2019
d9d191f
Relocates uniter access control method generation to a new module for…
manadart Jun 20, 2019
ee944e0
Moves event matchers from the modelcache_test package to core/cache/c…
manadart Jun 21, 2019
b78e03e
Adds new testing infrastructure for filling a cache with objects from…
manadart Jun 21, 2019
b345347
Internalises events notification channel in testing cache controller.
manadart Jun 21, 2019
32e0618
Makes cachetest event matchers into function declarations instead of …
manadart Jun 21, 2019
f402984
Adds copyright header to new cachetest matchers module.
manadart Jun 21, 2019
7671273
Merge pull request #10366 from manadart/2.6-cache-testing-infrastructure
jujubot Jun 21, 2019
fec148b
Merge branch 'upstream/2.6' into 2.6-into-develop
manadart Jun 21, 2019
e89fa76
Removes call to deprecated WantsVote method in cachetest package.
manadart Jun 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion provider/ec2/environ.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ func (e *environ) StartInstance(ctx context.ProviderCallContext, args environs.S
}

switch {
case subnetErr != nil && errors.IsNotFound(subnetErr):
case isNotFoundError(subnetErr):
return nil, errors.Trace(subnetErr)
case subnetErr != nil:
return nil, errors.Annotatef(maybeConvertCredentialError(subnetErr, ctx), "getting subnets for zone %q", availabilityZone)
Expand Down
9 changes: 6 additions & 3 deletions provider/gce/google/conn_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,19 @@ func (gce *Connection) Instances(prefix string, statuses ...string) ([]Instance,
func (gce *Connection) removeInstance(id, zone string) error {
err := gce.raw.RemoveInstance(gce.projectID, zone, id)
if err != nil {
if IsNotFound(err) {
return nil
}
// TODO(ericsnow) Try removing the firewall anyway?
return errors.Trace(err)
}

fwname := id
err = gce.raw.RemoveFirewall(gce.projectID, fwname)
if errors.IsNotFound(err) {
return nil
}
if err != nil {
if IsNotFound(err) {
return nil
}
return errors.Trace(err)
}
return nil
Expand Down
5 changes: 3 additions & 2 deletions provider/gce/google/conn_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,13 @@ func (s *connSuite) TestConnectionAddInstanceFailed(c *gc.C) {
func (s *connSuite) TestConnectionAddInstanceWaitFailed(c *gc.C) {
s.FakeConn.Instance = &s.RawInstanceFull

failure := s.NewWaitError(nil, errors.New("unknown"))
cause := errors.New("unknown")
failure := s.NewWaitError(nil, cause)
s.FakeConn.Err = failure

err := google.ConnAddInstance(s.Conn, &s.RawInstance, "mtype", "a-zone")

c.Check(errors.Cause(err), gc.Equals, failure)
c.Check(errors.Cause(err), gc.Equals, cause)
}

func (s *connSuite) TestConnectionAddInstanceGetFailed(c *gc.C) {
Expand Down
2 changes: 1 addition & 1 deletion provider/gce/google/conn_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
// returned.
func (gce Connection) firewallRules(fwname string) (ruleSet, error) {
firewalls, err := gce.raw.GetFirewalls(gce.projectID, fwname)
if errors.IsNotFound(err) {
if IsNotFound(err) {
return make(ruleSet), nil
}
if err != nil {
Expand Down
36 changes: 26 additions & 10 deletions provider/gce/google/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/juju/errors"
"google.golang.org/api/googleapi"

"github.com/juju/juju/environs/context"
)
Expand Down Expand Up @@ -90,20 +91,24 @@ func HasDenialStatusCode(err error) bool {
return false
}

// http/url.Error is constructed with status code in mind and, at the time of writing for go-1.10,
// contains response status code and description in error.Error.
// We have to examine the error message to determine whether the error is related to authentication failure.
if cause, ok := errors.Cause(err).(*url.Error); ok {
for code, descs := range AuthorisationFailureStatusCodes {
for _, desc := range descs {
if strings.Contains(cause.Error(), fmt.Sprintf(": %v %v", code, desc)) {
return true
}
var cause error
switch e := errors.Cause(err).(type) {
case *url.Error:
cause = e
case *googleapi.Error:
cause = e
default:
return false
}

for code, descs := range AuthorisationFailureStatusCodes {
for _, desc := range descs {
if strings.Contains(cause.Error(), fmt.Sprintf(": %v %v", code, desc)) {
return true
}
}
}
return false

}

// AuthorisationFailureStatusCodes contains http status code and
Expand All @@ -120,3 +125,14 @@ var AuthorisationFailureStatusCodes = map[int][]string{
// https://tools.ietf.org/html/rfc6749#section-5.2
http.StatusBadRequest: {"Bad Request"},
}

// IsNotFound reports if given error is of 'not found' type.
func IsNotFound(err error) bool {
if err == nil {
return false
}
if gerr, ok := errors.Cause(err).(*googleapi.Error); ok {
return gerr.Code == http.StatusNotFound
}
return errors.IsNotFound(errors.Cause(err))
}
63 changes: 45 additions & 18 deletions provider/gce/google/raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ func (rc *rawConn) AddInstance(projectID, zoneName string, spec *compute.Instanc
// We are guaranteed the insert failed at the point.
return errors.Annotate(err, "sending new instance request")
}

err = rc.waitOperation(projectID, operation, attemptsLong)
err = rc.waitOperation(projectID, operation, attemptsLong, logOperationErrors)
return errors.Trace(err)
}

Expand All @@ -111,8 +110,7 @@ func (rc *rawConn) RemoveInstance(projectID, zone, id string) error {
if err != nil {
return errors.Trace(err)
}

err = rc.waitOperation(projectID, operation, attemptsLong)
err = rc.waitOperation(projectID, operation, attemptsLong, returnNotFoundOperationErrors)
return errors.Trace(err)
}

Expand Down Expand Up @@ -145,8 +143,7 @@ func (rc *rawConn) AddFirewall(projectID string, firewall *compute.Firewall) err
if err != nil {
return errors.Trace(err)
}

err = rc.waitOperation(projectID, operation, attemptsLong)
err = rc.waitOperation(projectID, operation, attemptsLong, logOperationErrors)
return errors.Trace(err)
}

Expand All @@ -156,19 +153,45 @@ func (rc *rawConn) UpdateFirewall(projectID, name string, firewall *compute.Fire
if err != nil {
return errors.Trace(err)
}

err = rc.waitOperation(projectID, operation, attemptsLong)
err = rc.waitOperation(projectID, operation, attemptsLong, logOperationErrors)
return errors.Trace(err)
}

type handleOperationErrors func(operation *compute.Operation) error

func returnNotFoundOperationErrors(operation *compute.Operation) error {
if operation.Error != nil {
result := waitError{operation, nil}
for _, err := range operation.Error.Errors {
if err.Code == "RESOURCE_NOT_FOUND" {
result.cause = errors.NotFoundf("resource", err.Message)
continue
}
logger.Errorf("GCE operation error: (%s) %s", err.Code, err.Message)
}
return result
}
return nil
}

func logOperationErrors(operation *compute.Operation) error {
if operation.Error != nil {
for _, err := range operation.Error.Errors {
logger.Errorf("GCE operation error: (%s) %s", err.Code, err.Message)
}
return waitError{operation, nil}
}
return nil
}

func (rc *rawConn) RemoveFirewall(projectID, name string) error {
call := rc.Firewalls.Delete(projectID, name)
operation, err := call.Do()
if err != nil {
return errors.Trace(convertRawAPIError(err))
}

err = rc.waitOperation(projectID, operation, attemptsLong)
err = rc.waitOperation(projectID, operation, attemptsLong, returnNotFoundOperationErrors)
return errors.Trace(convertRawAPIError(err))
}

Expand Down Expand Up @@ -216,7 +239,7 @@ func (rc *rawConn) CreateDisk(project, zone string, spec *compute.Disk) error {
if err != nil {
return errors.Annotate(err, "could not create a new disk")
}
return errors.Trace(rc.waitOperation(project, op, attemptsLong))
return errors.Trace(rc.waitOperation(project, op, attemptsLong, logOperationErrors))
}

func (rc *rawConn) ListDisks(project string) ([]*compute.Disk, error) {
Expand Down Expand Up @@ -246,7 +269,7 @@ func (rc *rawConn) RemoveDisk(project, zone, id string) error {
if err != nil {
return errors.Annotatef(err, "could not delete disk %q", id)
}
return errors.Trace(rc.waitOperation(project, op, attemptsLong))
return errors.Trace(rc.waitOperation(project, op, attemptsLong, returnNotFoundOperationErrors))
}

func (rc *rawConn) GetDisk(project, zone, id string) (*compute.Disk, error) {
Expand Down Expand Up @@ -307,6 +330,13 @@ func (err waitError) Error() string {
return fmt.Sprintf("GCE operation %q failed", err.op.Name)
}

func (err waitError) Cause() error {
if err.cause != nil {
return err.cause
}
return err
}

func isWaitError(err error) bool {
_, ok := err.(*waitError)
return ok
Expand Down Expand Up @@ -347,7 +377,7 @@ var doOpCall = func(call opDoer) (*compute.Operation, error) {
// attempts) and may time out.
//
// TODO(katco): 2016-08-09: lp:1611427
func (rc *rawConn) waitOperation(projectID string, op *compute.Operation, attempts utils.AttemptStrategy) error {
func (rc *rawConn) waitOperation(projectID string, op *compute.Operation, attempts utils.AttemptStrategy, f handleOperationErrors) error {
// TODO(perrito666) 2016-05-02 lp:1558657
started := time.Now()
logger.Infof("GCE operation %q, waiting...", op.Name)
Expand All @@ -367,11 +397,8 @@ func (rc *rawConn) waitOperation(projectID string, op *compute.Operation, attemp
err := errors.Errorf("timed out after %d seconds", time.Now().Sub(started)/time.Second)
return waitError{op, err}
}
if op.Error != nil {
for _, err := range op.Error.Errors {
logger.Errorf("GCE operation error: (%s) %s", err.Code, err.Message)
}
return waitError{op, nil}
if err := f(op); err != nil {
return err
}

logger.Infof("GCE operation %q finished", op.Name)
Expand All @@ -394,7 +421,7 @@ func (rc *rawConn) SetMetadata(projectID, zone, instanceID string, metadata *com
if err != nil {
return errors.Trace(err)
}
err = rc.waitOperation(projectID, op, attemptsLong)
err = rc.waitOperation(projectID, op, attemptsLong, logOperationErrors)
return errors.Trace(err)
}

Expand Down
18 changes: 10 additions & 8 deletions provider/gce/google/raw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ type rawConnSuite struct {
// TODO(katco): 2016-08-09: lp:1611427
strategy utils.AttemptStrategy

callCount int
opCallErr error
handleOperationErrorsF handleOperationErrors
callCount int
opCallErr error
}

var _ = gc.Suite(&rawConnSuite{})
Expand All @@ -45,6 +46,7 @@ func (s *rawConnSuite) SetUpTest(c *gc.C) {
s.callCount++
return s.op, s.opCallErr
})
s.handleOperationErrorsF = logOperationErrors
}

func (s *rawConnSuite) TestConnectionCheckOperationError(c *gc.C) {
Expand Down Expand Up @@ -88,7 +90,7 @@ func (s *rawConnSuite) TestConnectionCheckOperationGlobal(c *gc.C) {

func (s *rawConnSuite) TestConnectionWaitOperation(c *gc.C) {
original := &compute.Operation{}
err := s.rawConn.waitOperation("proj", original, s.strategy)
err := s.rawConn.waitOperation("proj", original, s.strategy, s.handleOperationErrorsF)

c.Check(err, jc.ErrorIsNil)
c.Check(s.callCount, gc.Equals, 1)
Expand All @@ -98,7 +100,7 @@ func (s *rawConnSuite) TestConnectionWaitOperationAlreadyDone(c *gc.C) {
original := &compute.Operation{
Status: StatusDone,
}
err := s.rawConn.waitOperation("proj", original, s.strategy)
err := s.rawConn.waitOperation("proj", original, s.strategy, s.handleOperationErrorsF)

c.Check(err, jc.ErrorIsNil)
c.Check(s.callCount, gc.Equals, 0)
Expand All @@ -115,15 +117,15 @@ func (s *rawConnSuite) TestConnectionWaitOperationWaiting(c *gc.C) {
})

original := &compute.Operation{}
err := s.rawConn.waitOperation("proj", original, s.strategy)
err := s.rawConn.waitOperation("proj", original, s.strategy, s.handleOperationErrorsF)

c.Check(err, jc.ErrorIsNil)
c.Check(s.callCount, gc.Equals, 2)
}

func (s *rawConnSuite) TestConnectionWaitOperationTimeout(c *gc.C) {
s.op.Status = StatusRunning
err := s.rawConn.waitOperation("proj", s.op, s.strategy)
err := s.rawConn.waitOperation("proj", s.op, s.strategy, s.handleOperationErrorsF)

c.Check(err, gc.ErrorMatches, ".* timed out .*")
c.Check(s.callCount, gc.Equals, 4)
Expand All @@ -133,7 +135,7 @@ func (s *rawConnSuite) TestConnectionWaitOperationFailure(c *gc.C) {
s.opCallErr = errors.New("<unknown>")

original := &compute.Operation{}
err := s.rawConn.waitOperation("proj", original, s.strategy)
err := s.rawConn.waitOperation("proj", original, s.strategy, s.handleOperationErrorsF)

c.Check(err, gc.ErrorMatches, ".*<unknown>")
c.Check(s.callCount, gc.Equals, 1)
Expand All @@ -144,7 +146,7 @@ func (s *rawConnSuite) TestConnectionWaitOperationError(c *gc.C) {
s.op.Name = "testing-wait-operation-error"

original := &compute.Operation{}
err := s.rawConn.waitOperation("proj", original, s.strategy)
err := s.rawConn.waitOperation("proj", original, s.strategy, s.handleOperationErrorsF)

c.Check(err, gc.ErrorMatches, `.* "testing-wait-operation-error" .*`)
c.Check(s.callCount, gc.Equals, 1)
Expand Down
8 changes: 4 additions & 4 deletions provider/oci/storage_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,8 @@ func (v *volumeSource) attachVolume(ctx envcontext.ProviderCallContext, param st
req := ociCore.DetachVolumeRequest{
VolumeAttachmentId: volAttach.GetId(),
}
_, nestedErr := v.computeAPI.DetachVolume(context.Background(), req)
if nestedErr != nil {
res, nestedErr := v.computeAPI.DetachVolume(context.Background(), req)
if nestedErr != nil && !v.env.isNotFound(res.RawResponse) {
logger.Warningf("failed to cleanup volume attachment: %v", volAttach.GetId())
return
}
Expand Down Expand Up @@ -625,8 +625,8 @@ func (v *volumeSource) DetachVolumes(ctx envcontext.ProviderCallContext, params
VolumeAttachmentId: attachment.Id,
}

_, err := v.computeAPI.DetachVolume(context.Background(), request)
if err != nil {
res, err := v.computeAPI.DetachVolume(context.Background(), request)
if err != nil && !v.env.isNotFound(res.RawResponse) {
if isAuthFailure(err, ctx) {
credErr = err
common.HandleCredentialError(err, ctx)
Expand Down
Loading