Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2014 Canonical Ltd. | 1 // Copyright 2014 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package upgrades | 4 package upgrades |
5 | 5 |
6 import ( | 6 import ( |
7 "fmt" | 7 "fmt" |
8 | 8 |
9 "launchpad.net/juju-core/state/api" | 9 "launchpad.net/juju-core/state/api" |
10 "launchpad.net/juju-core/version" | 10 "launchpad.net/juju-core/version" |
11 ) | 11 ) |
12 | 12 |
13 // UpgradeStep defines an idempotent operation that is run to perform | 13 // UpgradeStep defines an idempotent operation that is run to perform |
14 // a specific upgrade step. | 14 // a specific upgrade step. |
15 type UpgradeStep interface { | 15 type UpgradeStep interface { |
rog
2014/02/13 09:26:29
Given that this is the upgrades package, perhaps
"
| |
16 // Description is a human readable description of what the upgrade step does. | 16 // Description is a human readable description of what the upgrade step does. |
dimitern
2014/02/12 09:30:01
Put some blank lines between the doc comment/metho
| |
17 Description() string | 17 Description() string |
18 // Targets returns the target machine types for which the upgrade step i s applicable. | 18 // Targets returns the target machine types for which the upgrade step i s applicable. |
19 Targets() []UpgradeTarget | 19 Targets() []UpgradeTarget |
20 // Run executes the upgrade business logic. | 20 // Run executes the upgrade business logic. |
21 » Run() error | 21 » Run(context Context) error |
22 } | 22 } |
23 | 23 |
24 // UpgradeOperation defines what steps to perform to upgrade to a target version . | 24 // UpgradeOperation defines what steps to perform to upgrade to a target version . |
25 type UpgradeOperation interface { | 25 type UpgradeOperation interface { |
26 // The Juju version for which this operation is applicable. | 26 // The Juju version for which this operation is applicable. |
27 // Upgrade operations designed for versions of Juju earlier | 27 // Upgrade operations designed for versions of Juju earlier |
28 // than we are upgrading from are not run since such steps would | 28 // than we are upgrading from are not run since such steps would |
29 // already have been used to get to the version we are running now. | 29 // already have been used to get to the version we are running now. |
30 TargetVersion() version.Number | 30 TargetVersion() version.Number |
31 // Steps to perform during an upgrade. | 31 // Steps to perform during an upgrade. |
32 Steps() []UpgradeStep | 32 Steps() []UpgradeStep |
33 } | 33 } |
34 | 34 |
35 // UpgradeTarget defines the type of machine for which a particular upgrade | 35 // UpgradeTarget defines the type of machine for which a particular upgrade |
36 // step can be run. | 36 // step can be run. |
37 type UpgradeTarget string | 37 type UpgradeTarget string |
38 | 38 |
39 const ( | 39 const ( |
40 // HostMachine is a machine on which units are deployed. | 40 // HostMachine is a machine on which units are deployed. |
41 HostMachine = UpgradeTarget("hostMachine") | 41 HostMachine = UpgradeTarget("hostMachine") |
42 // StateServer is a machine participating in a Juju state server cluster . | 42 // StateServer is a machine participating in a Juju state server cluster . |
dimitern
2014/02/12 09:30:01
Here as well - blank lines between.
| |
43 StateServer = UpgradeTarget("stateServer") | 43 StateServer = UpgradeTarget("stateServer") |
44 ) | 44 ) |
45 | 45 |
46 // upgradeToVersion encapsulates the steps which need to be run to | 46 // upgradeToVersion encapsulates the steps which need to be run to |
47 // upgrade any prior version of Juju to targetVersion. | 47 // upgrade any prior version of Juju to targetVersion. |
48 type upgradeToVersion struct { | 48 type upgradeToVersion struct { |
49 targetVersion version.Number | 49 targetVersion version.Number |
50 steps []UpgradeStep | 50 steps []UpgradeStep |
51 } | 51 } |
52 | 52 |
53 // Steps is defined on the UpgradeOperation interface. | 53 // Steps is defined on the UpgradeOperation interface. |
54 func (u upgradeToVersion) Steps() []UpgradeStep { | 54 func (u upgradeToVersion) Steps() []UpgradeStep { |
55 return u.steps | 55 return u.steps |
56 } | 56 } |
57 | 57 |
58 // TargetVersion is defined on the UpgradeOperation interface. | 58 // TargetVersion is defined on the UpgradeOperation interface. |
59 func (u upgradeToVersion) TargetVersion() version.Number { | 59 func (u upgradeToVersion) TargetVersion() version.Number { |
60 return u.targetVersion | 60 return u.targetVersion |
61 } | 61 } |
62 | 62 |
63 // Context is used give the upgrade steps attributes needed | 63 // Context is used give the upgrade steps attributes needed |
64 // to do their job. | 64 // to do their job. |
65 type Context interface { | 65 type Context interface { |
rog
2014/02/13 09:26:29
I don't really see the point of defining both this
| |
66 // APIState returns an API connection to state. | 66 // APIState returns an API connection to state. |
67 APIState() *api.State | 67 APIState() *api.State |
68 } | 68 } |
69 | 69 |
70 // UpgradeContext is a default Context implementation. | 70 // UpgradeContext is a default Context implementation. |
71 type UpgradeContext struct { | 71 type UpgradeContext struct { |
72 // Work in progress........ | 72 // Work in progress........ |
73 // Exactly what a context needs is to be determined as the | 73 // Exactly what a context needs is to be determined as the |
74 // implementation evolves. | 74 // implementation evolves. |
75 st *api.State | 75 st *api.State |
76 } | 76 } |
77 | 77 |
78 // APIState is defined on the Context interface. | 78 // APIState is defined on the Context interface. |
79 func (c *UpgradeContext) APIState() *api.State { | 79 func (c *UpgradeContext) APIState() *api.State { |
80 return c.st | 80 return c.st |
81 } | 81 } |
82 | 82 |
83 // upgradeOperation provides base attributes for any upgrade step. | 83 // upgradeOperation provides base attributes for any upgrade step. |
84 type upgradeOperation struct { | 84 type upgradeOperation struct { |
85 description string | 85 description string |
86 targets []UpgradeTarget | 86 targets []UpgradeTarget |
87 st *api.State | |
88 } | 87 } |
89 | 88 |
90 // Description is defined on the UpgradeStep interface. | 89 // Description is defined on the UpgradeStep interface. |
91 func (u *upgradeOperation) Description() string { | 90 func (u *upgradeOperation) Description() string { |
92 return u.description | 91 return u.description |
93 } | 92 } |
94 | 93 |
95 // Targets is defined on the UpgradeStep interface. | 94 // Targets is defined on the UpgradeStep interface. |
96 func (u *upgradeOperation) Targets() []UpgradeTarget { | 95 func (u *upgradeOperation) Targets() []UpgradeTarget { |
97 return u.targets | 96 return u.targets |
(...skipping 14 matching lines...) Expand all Loading... | |
112 func PerformUpgrade(from version.Number, target UpgradeTarget, context Context) *upgradeError { | 111 func PerformUpgrade(from version.Number, target UpgradeTarget, context Context) *upgradeError { |
113 // If from is not known, it is 1.16. | 112 // If from is not known, it is 1.16. |
114 if from == version.Zero { | 113 if from == version.Zero { |
115 from = version.MustParse("1.16.0") | 114 from = version.MustParse("1.16.0") |
116 } | 115 } |
117 for _, upgradeOps := range upgradeOperations(context) { | 116 for _, upgradeOps := range upgradeOperations(context) { |
118 // Do not run steps for versions of Juju earlier or same as we a re upgrading from. | 117 // Do not run steps for versions of Juju earlier or same as we a re upgrading from. |
119 if upgradeOps.TargetVersion().LessEqual(from) { | 118 if upgradeOps.TargetVersion().LessEqual(from) { |
120 continue | 119 continue |
121 } | 120 } |
122 » » if err := runUpgradeSteps(target, upgradeOps); err != nil { | 121 » » if err := runUpgradeSteps(context, target, upgradeOps); err != n il { |
123 return err | 122 return err |
124 } | 123 } |
125 } | 124 } |
126 return nil | 125 return nil |
127 } | 126 } |
128 | 127 |
129 // validTarget returns true if target is in step.Targets(). | 128 // validTarget returns true if target is in step.Targets(). |
130 func validTarget(target UpgradeTarget, step UpgradeStep) bool { | 129 func validTarget(target UpgradeTarget, step UpgradeStep) bool { |
131 for _, opTarget := range step.Targets() { | 130 for _, opTarget := range step.Targets() { |
132 if target == opTarget { | 131 if target == opTarget { |
133 return true | 132 return true |
134 } | 133 } |
135 } | 134 } |
136 return len(step.Targets()) == 0 | 135 return len(step.Targets()) == 0 |
137 } | 136 } |
138 | 137 |
139 // runUpgradeSteps runs all the upgrade steps relevant to target. | 138 // runUpgradeSteps runs all the upgrade steps relevant to target. |
140 // As soon as any error is encountered, the operation is aborted since | 139 // As soon as any error is encountered, the operation is aborted since |
141 // subsequent steps may required successful completion of earlier ones. | 140 // subsequent steps may required successful completion of earlier ones. |
142 // The steps must be idempotent so that the entire upgrade operation can | 141 // The steps must be idempotent so that the entire upgrade operation can |
143 // be retried. | 142 // be retried. |
144 func runUpgradeSteps(target UpgradeTarget, upgradeOp UpgradeOperation) *upgradeE rror { | 143 func runUpgradeSteps(context Context, target UpgradeTarget, upgradeOp UpgradeOpe ration) *upgradeError { |
145 for _, step := range upgradeOp.Steps() { | 144 for _, step := range upgradeOp.Steps() { |
146 if !validTarget(target, step) { | 145 if !validTarget(target, step) { |
147 continue | 146 continue |
148 } | 147 } |
149 » » if err := step.Run(); err != nil { | 148 » » if err := step.Run(context); err != nil { |
150 return &upgradeError{ | 149 return &upgradeError{ |
151 description: step.Description(), | 150 description: step.Description(), |
152 err: err, | 151 err: err, |
153 } | 152 } |
154 } | 153 } |
155 } | 154 } |
156 return nil | 155 return nil |
157 } | 156 } |
LEFT | RIGHT |