collectObservedState queries the Docker daemon for all resources belonging to the given project and returns a structured snapshot. The project model is used to classify containers by service and to identify orphans, and to scope network/volume queries to declared resources.
(ctx context.Context, project *types.Project)
| 82 | // The project model is used to classify containers by service and to identify |
| 83 | // orphans, and to scope network/volume queries to declared resources. |
| 84 | func (s *composeService) collectObservedState(ctx context.Context, project *types.Project) (*ObservedState, error) { |
| 85 | state := &ObservedState{ |
| 86 | ProjectName: project.Name, |
| 87 | Containers: map[string][]ObservedContainer{}, |
| 88 | Networks: map[string]ObservedNetwork{}, |
| 89 | Volumes: map[string]ObservedVolume{}, |
| 90 | } |
| 91 | |
| 92 | // --- Containers --- |
| 93 | // Use oneOffInclude to detect orphaned one-off containers (matching the |
| 94 | // previous behavior of create() which used oneOffInclude + isOrphaned). |
| 95 | raw, err := s.getContainers(ctx, project.Name, oneOffInclude, true) |
| 96 | if err != nil { |
| 97 | return nil, err |
| 98 | } |
| 99 | |
| 100 | knownServices := map[string]bool{} |
| 101 | for _, svc := range project.Services { |
| 102 | knownServices[svc.Name] = true |
| 103 | state.Containers[svc.Name] = nil // ensure key exists even if empty |
| 104 | } |
| 105 | for _, ds := range project.DisabledServices { |
| 106 | knownServices[ds.Name] = true |
| 107 | } |
| 108 | |
| 109 | for _, c := range raw { |
| 110 | svcName := c.Labels[api.ServiceLabel] |
| 111 | if isNotOneOff(c) && knownServices[svcName] { |
| 112 | state.Containers[svcName] = append(state.Containers[svcName], toObservedContainer(c)) |
| 113 | } else if isOrphaned(project)(c) { |
| 114 | state.Orphans = append(state.Orphans, toObservedContainer(c)) |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | // --- Networks --- |
| 119 | nwList, err := s.apiClient().NetworkList(ctx, client.NetworkListOptions{ |
| 120 | Filters: projectFilter(project.Name), |
| 121 | }) |
| 122 | if err != nil { |
| 123 | return nil, err |
| 124 | } |
| 125 | for _, nw := range nwList.Items { |
| 126 | key := nw.Labels[api.NetworkLabel] |
| 127 | if key == "" { |
| 128 | continue |
| 129 | } |
| 130 | state.Networks[key] = ObservedNetwork{ |
| 131 | ID: nw.ID, |
| 132 | Name: nw.Name, |
| 133 | ConfigHash: nw.Labels[api.ConfigHashLabel], |
| 134 | ProjectName: nw.Labels[api.ProjectLabel], |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | // --- Volumes --- |
| 139 | volList, err := s.apiClient().VolumeList(ctx, client.VolumeListOptions{ |
| 140 | Filters: projectFilter(project.Name), |
| 141 | }) |