Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sqlite updates #17658

Merged
merged 9 commits into from
Mar 2, 2023
94 changes: 55 additions & 39 deletions libpod/sqlite_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1186,7 +1186,7 @@ func (s *SQLiteState) RewritePodConfig(pod *Pod, newCfg *PodConfig) (defErr erro
}
if rows == 0 {
pod.valid = false
return define.ErrNoSuchPod
return fmt.Errorf("no pod with ID %s found in DB: %w", pod.ID(), define.ErrNoSuchPod)
}

if err := tx.Commit(); err != nil {
Expand All @@ -1199,8 +1199,7 @@ func (s *SQLiteState) RewritePodConfig(pod *Pod, newCfg *PodConfig) (defErr erro
// RewriteVolumeConfig rewrites a volume's configuration.
// WARNING: This function is DANGEROUS. Do not use without reading the full
// comment on this function in state.go.
// TODO TODO TODO
func (s *SQLiteState) RewriteVolumeConfig(volume *Volume, newCfg *VolumeConfig) error {
func (s *SQLiteState) RewriteVolumeConfig(volume *Volume, newCfg *VolumeConfig) (defErr error) {
if !s.valid {
return define.ErrDBClosed
}
Expand All @@ -1209,38 +1208,41 @@ func (s *SQLiteState) RewriteVolumeConfig(volume *Volume, newCfg *VolumeConfig)
return define.ErrVolumeRemoved
}

return define.ErrNotImplemented

// newCfgJSON, err := json.Marshal(newCfg)
// if err != nil {
// return fmt.Errorf("marshalling new configuration JSON for volume %q: %w", volume.Name(), err)
// }

// db, err := s.getDBCon()
// if err != nil {
// return err
// }
// defer s.deferredCloseDBCon(db)
json, err := json.Marshal(newCfg)
if err != nil {
return fmt.Errorf("error marshalling volume %s new config JSON: %w", volume.Name(), err)
}

// err = db.Update(func(tx *bolt.Tx) error {
// volBkt, err := getVolBucket(tx)
// if err != nil {
// return err
// }
tx, err := s.conn.Begin()
if err != nil {
return fmt.Errorf("beginning transaction to rewrite volume %s config: %w", volume.Name(), err)
}
defer func() {
if defErr != nil {
if err := tx.Rollback(); err != nil {
logrus.Errorf("Rolling back transaction to rewrite volume %s config: %v", volume.Name(), err)
}
}
}()

// volDB := volBkt.Bucket([]byte(volume.Name()))
// if volDB == nil {
// volume.valid = false
// return fmt.Errorf("no volume with name %q found in DB: %w", volume.Name(), define.ErrNoSuchVolume)
// }
results, err := tx.Exec("UPDATE VolumeConfig SET Name=?, JSON=? WHERE ID=?;", newCfg.Name, json, volume.Name())
if err != nil {
return fmt.Errorf("updating volume config table with new configuration for volume %s: %w", volume.Name(), err)
}
rows, err := results.RowsAffected()
if err != nil {
return fmt.Errorf("retrieving volume %s config rewrite rows affected: %w", volume.Name(), err)
}
if rows == 0 {
volume.valid = false
return fmt.Errorf("no volume with name %q found in DB: %w", volume.Name(), define.ErrNoSuchVolume)
}

// if err := volDB.Put(configKey, newCfgJSON); err != nil {
// return fmt.Errorf("updating volume %q config JSON: %w", volume.Name(), err)
// }
if err := tx.Commit(); err != nil {
return fmt.Errorf("committing transaction to rewrite volume %s config: %w", volume.Name(), err)
}

// return nil
// })
// return err
return nil
}

// Pod retrieves a pod given its full ID
Expand Down Expand Up @@ -1470,6 +1472,19 @@ func (s *SQLiteState) AddPod(pod *Pod) (defErr error) {
}
}()

// TODO: explore whether there's a more idiomatic way to do error checks for the name.
// There is a sqlite3.ErrConstraintUnique error but I (vrothberg) couldn't find a way
// to work with the returned errors yet.
var check int
row := tx.QueryRow("SELECT 1 FROM PodConfig WHERE Name=?;", pod.Name())
if err := row.Scan(&check); err != nil {
if !errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("checking if pod name %s exists in database: %w", pod.Name(), err)
}
} else if check != 0 {
return fmt.Errorf("name \"%s\" is in use: %w", pod.Name(), define.ErrPodExists)
}

if _, err := tx.Exec("INSERT INTO IDNamespace VALUES (?);", pod.ID()); err != nil {
return fmt.Errorf("adding pod id to database: %w", err)
}
Expand Down Expand Up @@ -2033,25 +2048,26 @@ func (s *SQLiteState) LookupVolume(name string) (*Volume, error) {
return nil, define.ErrDBClosed
}

rows, err := s.conn.Query("SELECT JSON FROM VolumeConfig WHERE Name LIKE ?;", name+"%")
rows, err := s.conn.Query("SELECT Name, JSON FROM VolumeConfig WHERE Name LIKE ? ORDER BY LENGTH(Name) ASC;", name+"%")
if err != nil {
return nil, fmt.Errorf("querying database for volume %s: %w", name, err)
}
defer rows.Close()

var configJSON string
foundResult := false
var foundName, configJSON string
for rows.Next() {
if foundResult {
if foundName != "" {
return nil, fmt.Errorf("more than one result for volume name %s: %w", name, define.ErrVolumeExists)
}
if err := rows.Scan(&configJSON); err != nil {
if err := rows.Scan(&foundName, &configJSON); err != nil {
return nil, fmt.Errorf("retrieving volume %s config from database: %w", name, err)
}
foundResult = true
if foundName == name {
break
}
}
if !foundResult {
return nil, define.ErrNoSuchVolume
if foundName == "" {
return nil, fmt.Errorf("no volume with name %q found: %w", name, define.ErrNoSuchVolume)
}

vol := new(Volume)
Expand Down
19 changes: 16 additions & 3 deletions libpod/sqlite_state_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func (s *SQLiteState) rewriteContainerConfig(ctr *Container, newCfg *ContainerCo
}
}()

results, err := tx.Exec("UPDATE TABLE ContainerConfig SET Name=?, JSON=? WHERE ID=?;", newCfg.Name, json, ctr.ID())
results, err := tx.Exec("UPDATE ContainerConfig SET Name=?, JSON=? WHERE ID=?;", newCfg.Name, json, ctr.ID())
if err != nil {
return fmt.Errorf("updating container config table with new configuration for container %s: %w", ctr.ID(), err)
}
Expand All @@ -339,6 +339,12 @@ func (s *SQLiteState) rewriteContainerConfig(ctr *Container, newCfg *ContainerCo
}

func (s *SQLiteState) addContainer(ctr *Container) (defErr error) {
for net := range ctr.config.Networks {
opts := ctr.config.Networks[net]
opts.Aliases = append(opts.Aliases, ctr.config.ID[:12])
ctr.config.Networks[net] = opts
}

configJSON, err := json.Marshal(ctr.config)
if err != nil {
return fmt.Errorf("marshalling container config json: %w", err)
Expand Down Expand Up @@ -399,9 +405,13 @@ func (s *SQLiteState) addContainer(ctr *Container) (defErr error) {
return fmt.Errorf("adding container dependency %s to database: %w", dep, err)
}
}
volMap := make(map[string]bool)
for _, vol := range ctr.config.NamedVolumes {
if _, err := tx.Exec("INSERT INTO ContainerVolume VALUES (?, ?);", ctr.ID(), vol.Name); err != nil {
return fmt.Errorf("adding container volume %s to database: %w", vol.Name, err)
if _, ok := volMap[vol.Name]; !ok {
if _, err := tx.Exec("INSERT INTO ContainerVolume VALUES (?, ?);", ctr.ID(), vol.Name); err != nil {
return fmt.Errorf("adding container volume %s to database: %w", vol.Name, err)
}
volMap[vol.Name] = true
}
}

Expand Down Expand Up @@ -499,6 +509,9 @@ func (s *SQLiteState) networkModify(ctr *Container, network string, opts types.P
}

if !disconnect {
if newCfg.Networks == nil {
newCfg.Networks = make(map[string]types.PerNetworkOptions)
}
newCfg.Networks[network] = opts
} else {
delete(newCfg.Networks, network)
Expand Down