From 6b7b4b03a888b2d87dd58d1e8048d2a5c7e6a36b Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 28 Jan 2018 05:31:01 -0500 Subject: Add pod removal code Signed-off-by: Matthew Heon Closes: #268 Approved by: rhatdan --- libpod/sql_state.go | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) (limited to 'libpod/sql_state.go') diff --git a/libpod/sql_state.go b/libpod/sql_state.go index 373f1250d..b7fd0dac7 100644 --- a/libpod/sql_state.go +++ b/libpod/sql_state.go @@ -604,7 +604,6 @@ func (s *SQLState) LookupPod(idOrName string) (*Pod, error) { return nil, errors.Wrapf(ErrNoSuchCtr, "no pod with ID or name %s found", idOrName) } - return pod, nil } @@ -652,7 +651,6 @@ func (s *SQLState) PodHasContainer(pod *Pod, ctrID string) (bool, error) { return false, errors.Wrapf(ErrInternal, "check digit for PodHasContainer query incorrect") } - return true, nil } @@ -704,7 +702,6 @@ func (s *SQLState) PodContainersByID(pod *Pod) ([]string, error) { return nil, errors.Wrapf(err, "error retrieving container rows") } - return containers, nil } @@ -820,7 +817,7 @@ func (s *SQLState) RemovePod(pod *Pod) error { // Check rows acted on for the first transaction, verify we actually removed something result, err := tx.Exec(query, pod.ID()) if err != nil { - return errors.Wrapf(err, "error removing pod %s from containers table", pod.ID()) + return errors.Wrapf(err, "error removing pod %s from pods table", pod.ID()) } rows, err := result.RowsAffected() if err != nil { @@ -836,6 +833,108 @@ func (s *SQLState) RemovePod(pod *Pod) error { return nil } +// RemovePodContainers removes all containers in a pod simultaneously +// This can avoid issues with dependencies within the pod +// The operation will fail if any container in the pod has a dependency from +// outside the pod +func (s *SQLState) RemovePodContainers(pod *Pod) error { + const ( + getPodCtrs = "SELECT Id FROM containers WHERE pod=?;" + removeCtr = "DELETE FROM containers WHERE pod=?;" + removeCtrState = "DELETE FROM containerState WHERE ID=ANY(SELECT Id FROM containers WHERE pod=?);" + ) + + if !s.valid { + return ErrDBClosed + } + + if !pod.valid { + return ErrPodRemoved + } + + committed := false + + tx, err := s.db.Begin() + if err != nil { + return errors.Wrapf(err, "error beginning database transaction") + } + defer func() { + if err != nil && !committed { + if err2 := tx.Rollback(); err2 != nil { + logrus.Errorf("Error rolling back transaction to remove pod %s containers: %v", pod.ID(), err2) + } + } + }() + + // First get all containers in the pod + rows, err := tx.Query(getPodCtrs, pod.ID()) + if err != nil { + return errors.Wrapf(err, "error retrieving containers from database") + } + defer rows.Close() + + containers := []string{} + + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + if err == sql.ErrNoRows { + return ErrNoSuchCtr + } + + return errors.Wrapf(err, "error parsing database row into container ID") + } + + containers = append(containers, id) + } + if err := rows.Err(); err != nil { + return errors.Wrapf(err, "error retrieving container rows") + } + + // Have container IDs, now exec SQL to remove contianers in the pod + // Remove state first, as it needs the subquery on containers + // Don't bother checking if we actually removed anything, we just want to + // empty the pod + _, err = tx.Exec(removeCtrState, pod.ID()) + if err != nil { + return errors.Wrapf(err, "error removing pod %s containers from state table", pod.ID()) + } + + _, err = tx.Exec(removeCtr, pod.ID()) + if err != nil { + return errors.Wrapf(err, "error removing pod %s containers from containers table", pod.ID()) + } + + if err := tx.Commit(); err != nil { + return errors.Wrapf(err, "error committing transaction to add pod %s", pod.ID()) + } + + committed = true + + // Remove JSON files from the containers in question + hasError := false + for _, ctr := range containers { + jsonPath := getSpecPath(s.specsDir, ctr) + if err := os.Remove(jsonPath); err != nil { + logrus.Errorf("Error removing spec JSON for container %s: %v", ctr, err) + hasError = true + } + + portsPath := getPortsPath(s.specsDir, ctr) + if err := os.Remove(portsPath); err != nil { + if !os.IsNotExist(err) { + logrus.Errorf("Error removing ports JSON for container %s: %v", ctr, err) + hasError = true + } + } + } + if hasError { + return errors.Wrapf(ErrInternal, "error removing JSON state for some containers") + } + + return nil +} + // AddContainerToPod adds a container to the given pod func (s *SQLState) AddContainerToPod(pod *Pod, ctr *Container) error { if !pod.valid { -- cgit v1.2.3-54-g00ecf