| package manager |
| |
| import ( |
| "reflect" |
| |
| "github.com/docker/swarmkit/api" |
| "github.com/docker/swarmkit/manager/state/store" |
| ) |
| |
| // IsStateDirty returns true if any objects have been added to raft which make |
| // the state "dirty". Currently, the existence of any object other than the |
| // default cluster or the local node implies a dirty state. |
| func (m *Manager) IsStateDirty() (bool, error) { |
| var ( |
| storeSnapshot *api.StoreSnapshot |
| err error |
| ) |
| m.raftNode.MemoryStore().View(func(readTx store.ReadTx) { |
| storeSnapshot, err = m.raftNode.MemoryStore().Save(readTx) |
| }) |
| |
| if err != nil { |
| return false, err |
| } |
| |
| // Check Nodes and Clusters fields. |
| nodeID := m.config.SecurityConfig.ClientTLSCreds.NodeID() |
| if len(storeSnapshot.Nodes) > 1 || (len(storeSnapshot.Nodes) == 1 && storeSnapshot.Nodes[0].ID != nodeID) { |
| return true, nil |
| } |
| |
| clusterID := m.config.SecurityConfig.ClientTLSCreds.Organization() |
| if len(storeSnapshot.Clusters) > 1 || (len(storeSnapshot.Clusters) == 1 && storeSnapshot.Clusters[0].ID != clusterID) { |
| return true, nil |
| } |
| |
| // Use reflection to check that other fields don't have values. This |
| // lets us implement a whitelist-type approach, where we don't need to |
| // remember to add individual types here. |
| |
| val := reflect.ValueOf(*storeSnapshot) |
| numFields := val.NumField() |
| |
| for i := 0; i != numFields; i++ { |
| field := val.Field(i) |
| structField := val.Type().Field(i) |
| if structField.Type.Kind() != reflect.Slice { |
| panic("unexpected field type in StoreSnapshot") |
| } |
| if structField.Name != "Nodes" && structField.Name != "Clusters" && structField.Name != "Networks" && field.Len() != 0 { |
| // One of the other data types has an entry |
| return true, nil |
| } |
| } |
| |
| return false, nil |
| } |