@@ -117,50 +117,57 @@ impl ObservedPropolisState {
117
117
instance_runtime : & InstanceRuntimeState ,
118
118
propolis_state : & InstanceStateMonitorResponse ,
119
119
) -> Self {
120
- let migration_status =
121
- match ( instance_runtime. migration_id , & propolis_state. migration ) {
122
- // If the runtime state and Propolis state agree that there's
123
- // a migration in progress, and they agree on its ID, the
124
- // Propolis migration state determines the migration status.
125
- ( Some ( this_id) , Some ( propolis_migration) )
126
- if this_id == propolis_migration. migration_id =>
127
- {
128
- match propolis_migration. state {
129
- PropolisMigrationState :: Finish => {
130
- ObservedMigrationStatus :: Succeeded
131
- }
132
- PropolisMigrationState :: Error => {
133
- ObservedMigrationStatus :: Failed
134
- }
135
- _ => ObservedMigrationStatus :: InProgress ,
136
- }
137
- }
138
-
139
- // If both sides have a migration ID, but the IDs don't match,
140
- // assume the instance's migration ID is newer. This can happen
141
- // if Propolis was initialized via migration in and has not yet
142
- // been told to migrate out.
143
- ( Some ( _) , Some ( _) ) => ObservedMigrationStatus :: Pending ,
144
-
145
- // If only Propolis has a migration ID, assume it was from a
146
- // prior migration in and report that no migration is in
147
- // progress. This could be improved with propolis#508.
148
- ( None , Some ( _) ) => ObservedMigrationStatus :: NoMigration ,
149
-
150
- // A migration source's migration IDs get set before its
151
- // Propolis actually gets asked to migrate, so it's possible for
152
- // the runtime state to contain an ID while the Propolis has
153
- // none, in which case the migration is pending.
154
- ( Some ( _) , None ) => ObservedMigrationStatus :: Pending ,
155
-
156
- // If neither side has a migration ID, then there's clearly no
157
- // migration.
158
- ( None , None ) => ObservedMigrationStatus :: NoMigration ,
120
+ // If there's no migration currently registered with this sled, report
121
+ // the current state and that no migration is currently in progress,
122
+ // even if Propolis has some migration data to share. (This case arises
123
+ // when Propolis returns state from a previous migration that sled agent
124
+ // has already retired.)
125
+ //
126
+ // N.B. This needs to be read from the instance runtime state and not
127
+ // the migration runtime state to ensure that, once a migration in
128
+ // completes, the "completed" observation is reported to
129
+ // `InstanceStates::apply_propolis_observation` exactly once.
130
+ // Otherwise that routine will try to apply the "inbound migration
131
+ // complete" instance state transition twice.
132
+ let Some ( migration_id) = instance_runtime. migration_id else {
133
+ return Self {
134
+ vmm_state : PropolisInstanceState ( propolis_state. state ) ,
135
+ migration_status : ObservedMigrationStatus :: NoMigration ,
136
+ time : Utc :: now ( ) ,
159
137
} ;
138
+ } ;
139
+
140
+ // Sled agent believes a live migration may be in progress. See if
141
+ // either of the Propolis migrations corresponds to it.
142
+ let propolis_migration = match (
143
+ & propolis_state. migration . migration_in ,
144
+ & propolis_state. migration . migration_out ,
145
+ ) {
146
+ ( Some ( inbound) , _) if inbound. id == migration_id => inbound,
147
+ ( _, Some ( outbound) ) if outbound. id == migration_id => outbound,
148
+ _ => {
149
+ // Sled agent believes this instance should be migrating, but
150
+ // Propolis isn't reporting a matching migration yet, so assume
151
+ // the migration is still pending.
152
+ return Self {
153
+ vmm_state : PropolisInstanceState ( propolis_state. state ) ,
154
+ migration_status : ObservedMigrationStatus :: Pending ,
155
+ time : Utc :: now ( ) ,
156
+ } ;
157
+ }
158
+ } ;
160
159
161
160
Self {
162
161
vmm_state : PropolisInstanceState ( propolis_state. state ) ,
163
- migration_status,
162
+ migration_status : match propolis_migration. state {
163
+ PropolisMigrationState :: Finish => {
164
+ ObservedMigrationStatus :: Succeeded
165
+ }
166
+ PropolisMigrationState :: Error => {
167
+ ObservedMigrationStatus :: Failed
168
+ }
169
+ _ => ObservedMigrationStatus :: InProgress ,
170
+ } ,
164
171
time : Utc :: now ( ) ,
165
172
}
166
173
}
0 commit comments