(ctx context.Context, container containers.Container, fieldpaths ...string)
| 172 | } |
| 173 | |
| 174 | func (s *containerStore) Update(ctx context.Context, container containers.Container, fieldpaths ...string) (containers.Container, error) { |
| 175 | if container.ID == "" { |
| 176 | return containers.Container{}, fmt.Errorf("must specify a container id: %w", errdefs.ErrInvalidArgument) |
| 177 | } |
| 178 | |
| 179 | ctx, span := tracing.StartSpan(ctx, |
| 180 | tracing.Name(spanContainerPrefix, "Update"), |
| 181 | tracing.WithAttribute("container.id", container.ID), |
| 182 | tracing.WithNamespace(ctx), |
| 183 | ) |
| 184 | defer span.End() |
| 185 | if container.SandboxID != "" { |
| 186 | span.SetAttributes(tracing.Attribute("sandbox.id", container.SandboxID)) |
| 187 | } |
| 188 | namespace, err := namespaces.NamespaceRequired(ctx) |
| 189 | if err != nil { |
| 190 | return containers.Container{}, err |
| 191 | } |
| 192 | |
| 193 | var updated containers.Container |
| 194 | if err := update(ctx, s.db, func(tx *bolt.Tx) error { |
| 195 | bkt := getContainersBucket(tx, namespace) |
| 196 | if bkt == nil { |
| 197 | return fmt.Errorf("cannot update container %q in namespace %q: %w", container.ID, namespace, errdefs.ErrNotFound) |
| 198 | } |
| 199 | |
| 200 | cbkt := bkt.Bucket([]byte(container.ID)) |
| 201 | if cbkt == nil { |
| 202 | return fmt.Errorf("container %q: %w", container.ID, errdefs.ErrNotFound) |
| 203 | } |
| 204 | |
| 205 | if err := readContainer(&updated, cbkt); err != nil { |
| 206 | return fmt.Errorf("failed to read container %q: %w", container.ID, err) |
| 207 | } |
| 208 | createdat := updated.CreatedAt |
| 209 | updated.ID = container.ID |
| 210 | |
| 211 | if len(fieldpaths) == 0 { |
| 212 | // only allow updates to these field on full replace. |
| 213 | fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"} |
| 214 | |
| 215 | // Fields that are immutable must cause an error when no field paths |
| 216 | // are provided. This allows these fields to become mutable in the |
| 217 | // future. |
| 218 | if updated.Snapshotter != container.Snapshotter { |
| 219 | return fmt.Errorf("container.Snapshotter field is immutable: %w", errdefs.ErrInvalidArgument) |
| 220 | } |
| 221 | |
| 222 | if updated.Runtime.Name != container.Runtime.Name { |
| 223 | return fmt.Errorf("container.Runtime.Name field is immutable: %w", errdefs.ErrInvalidArgument) |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | // apply the field mask. If you update this code, you better follow the |
| 228 | // field mask rules in field_mask.proto. If you don't know what this |
| 229 | // is, do not update this code. |
| 230 | for _, path := range fieldpaths { |
| 231 | if strings.HasPrefix(path, "labels.") { |
nothing calls this directly
no test coverage detected