The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7386
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 72b248177ce376d598037f99a485b0bfab919fd8 Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Mon, 11 May 2020 11:19:21 +0100 Subject: [PATCH 1/8] lxd/db: Change UpdateCertificate to RenameCertificate (only renaming supported) Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/certificates.go | 2 +- lxd/db/certificates.go | 9 +++++---- lxd/db/certificates.mapper.go | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lxd/certificates.go b/lxd/certificates.go index fa817c1ee2..917f5d1178 100644 --- a/lxd/certificates.go +++ b/lxd/certificates.go @@ -322,7 +322,7 @@ func doCertificateUpdate(d *Daemon, fingerprint string, req api.CertificatePut) return response.BadRequest(fmt.Errorf("Unknown request type %s", req.Type)) } - err := d.cluster.UpdateCertificate(fingerprint, req.Name, 1) + err := d.cluster.RenameCertificate(fingerprint, req.Name) if err != nil { return response.SmartError(err) } diff --git a/lxd/db/certificates.go b/lxd/db/certificates.go index cfefaa773e..5176ceb29c 100644 --- a/lxd/db/certificates.go +++ b/lxd/db/certificates.go @@ -12,6 +12,7 @@ package db //go:generate mapper stmt -p db -e certificate id //go:generate mapper stmt -p db -e certificate create struct=Certificate //go:generate mapper stmt -p db -e certificate delete +//go:generate mapper stmt -p db -e certificate rename // //go:generate mapper method -p db -e certificate List //go:generate mapper method -p db -e certificate Get @@ -19,6 +20,7 @@ package db //go:generate mapper method -p db -e certificate Exists struct=Certificate //go:generate mapper method -p db -e certificate Create struct=Certificate //go:generate mapper method -p db -e certificate Delete +//go:generate mapper method -p db -e certificate Rename // Certificate is here to pass the certificates content // from the database around @@ -66,11 +68,10 @@ func (c *Cluster) DeleteCertificate(fingerprint string) error { return err } -// UpdateCertificate updates the certificate with the given fingerprint. -func (c *Cluster) UpdateCertificate(fingerprint string, certName string, certType int) error { +// RenameCertificate updates a certificate's name. +func (c *Cluster) RenameCertificate(fingerprint string, name string) error { err := c.Transaction(func(tx *ClusterTx) error { - _, err := tx.tx.Exec("UPDATE certificates SET name=?, type=? WHERE fingerprint=?", certName, certType, fingerprint) - return err + return c.RenameCertificate(fingerprint, name) }) return err } diff --git a/lxd/db/certificates.mapper.go b/lxd/db/certificates.mapper.go index 4f6e718358..c682094754 100644 --- a/lxd/db/certificates.mapper.go +++ b/lxd/db/certificates.mapper.go @@ -41,6 +41,10 @@ var certificateDelete = cluster.RegisterStmt(` DELETE FROM certificates WHERE fingerprint = ? `) +var certificateRename = cluster.RegisterStmt(` +UPDATE certificates SET name = ? WHERE fingerprint = ? +`) + // GetCertificates returns all available certificates. func (c *ClusterTx) GetCertificates(filter CertificateFilter) ([]Certificate, error) { // Result slice. @@ -203,3 +207,21 @@ func (c *ClusterTx) DeleteCertificate(fingerprint string) error { return nil } + +// RenameCertificate renames the certificate matching the given key parameters. +func (c *ClusterTx) RenameCertificate(fingerprint string, to string) error { + stmt := c.stmt(certificateRename) + result, err := stmt.Exec(to, fingerprint) + if err != nil { + return errors.Wrap(err, "Rename certificate") + } + + n, err := result.RowsAffected() + if err != nil { + return errors.Wrap(err, "Fetch affected rows") + } + if n != 1 { + return fmt.Errorf("Query affected %d rows instead of 1", n) + } + return nil +} From 1bb5dde03ee8174197bdea33dfe6446cb66e0f7e Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Mon, 11 May 2020 11:23:28 +0100 Subject: [PATCH 2/8] lxd/db: Rename containers.go to instances.go Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/db/{containers.go => instances.go} | 0 lxd/db/{containers_export_test.go => instances_export_test.go} | 0 lxd/db/{containers_test.go => instances_test.go} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename lxd/db/{containers.go => instances.go} (100%) rename lxd/db/{containers_export_test.go => instances_export_test.go} (100%) rename lxd/db/{containers_test.go => instances_test.go} (100%) diff --git a/lxd/db/containers.go b/lxd/db/instances.go similarity index 100% rename from lxd/db/containers.go rename to lxd/db/instances.go diff --git a/lxd/db/containers_export_test.go b/lxd/db/instances_export_test.go similarity index 100% rename from lxd/db/containers_export_test.go rename to lxd/db/instances_export_test.go diff --git a/lxd/db/containers_test.go b/lxd/db/instances_test.go similarity index 100% rename from lxd/db/containers_test.go rename to lxd/db/instances_test.go From 3ebe673c97af596794cc0a3cfa206902576da160 Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Mon, 11 May 2020 14:21:32 +0100 Subject: [PATCH 3/8] shared/generate/db: Statement for deleting references (config and devices) Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- shared/generate/db/stmt.go | 102 ++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 30 deletions(-) diff --git a/shared/generate/db/stmt.go b/shared/generate/db/stmt.go index 08f2d39adb..227733a655 100644 --- a/shared/generate/db/stmt.go +++ b/shared/generate/db/stmt.go @@ -50,6 +50,10 @@ func (s *Stmt) Generate(buf *file.Buffer) error { return s.createRef(buf) } + if strings.HasPrefix(s.kind, "delete") && strings.HasSuffix(s.kind, "-ref") { + return s.deleteRef(buf) + } + if strings.HasSuffix(s.kind, "-ref") || strings.Contains(s.kind, "-ref-by-") { return s.ref(buf) } @@ -417,7 +421,6 @@ func (s *Stmt) createRef(buf *file.Buffer) error { sql := fmt.Sprintf(stmts["create"], table, columns, params) s.register(buf, sql) - } else if field.Type.Name == "map[string]map[string]string" { // Assume this is a devices table columns := fmt.Sprintf("%s_id, name, type", s.entity) @@ -443,35 +446,7 @@ func (s *Stmt) id(buf *file.Buffer) error { if err != nil { return errors.Wrap(err, "Parse entity struct") } - nk := mapping.NaturalKey() - criteria := "" - for i, field := range nk { - if i > 0 { - criteria += " AND " - } - - var column string - if field.IsScalar() { - column = field.Config.Get("join") - } else { - column = mapping.FieldColumnName(field.Name) - } - - criteria += fmt.Sprintf("%s = ?", column) - } - - table := entityTable(s.entity) - for _, field := range mapping.ScalarFields() { - join := field.Config.Get("join") - right := strings.Split(join, ".")[0] - via := entityTable(s.entity) - if field.Config.Get("via") != "" { - via = entityTable(field.Config.Get("via")) - } - table += fmt.Sprintf(" JOIN %s ON %s.%s_id = %s.id", right, via, lex.Singular(right), right) - } - - sql := fmt.Sprintf(stmts[s.kind], entityTable(s.entity), table, criteria) + sql := naturalKeySelect(s.entity, mapping) s.register(buf, sql) return nil @@ -558,6 +533,38 @@ func (s *Stmt) delete(buf *file.Buffer) error { return nil } +func (s *Stmt) deleteRef(buf *file.Buffer) error { + // Base snake-case name of the references (e.g. "used-by-ref" -> "used_by") + name := strings.Replace(s.kind[len("create-"):strings.Index(s.kind, "-ref")], "-", "_", -1) + + // Field name of the reference + fieldName := lex.Camel(name) + + // Table name where reference objects can be fetched. + table := fmt.Sprintf("%s_%s", entityTable(s.entity), name) + + mapping, err := Parse(s.packages[s.pkg], lex.Camel(s.entity)) + if err != nil { + return err + } + + field := mapping.FieldByName(fieldName) + if field == nil { + return fmt.Errorf("Entity %s has no field named %s", s.entity, fieldName) + } + + where := fmt.Sprintf("%s_id = ?", s.entity) + + if field.Type.Name == "map[string]string" || field.Type.Name == "map[string]map[string]string" { + // Assume this is a config or devices table + sql := fmt.Sprintf(stmts["delete"], table, where) + s.register(buf, sql) + + } + + return nil +} + // Return a where clause that filters an entity by natural key. func naturalKeyWhere(mapping *Mapping) string { nk := mapping.NaturalKey() @@ -605,6 +612,41 @@ func naturalKeyWhere(mapping *Mapping) string { return strings.Join(where, " AND ") } +// Return a select statement that returns the ID of an entity given its natural key. +func naturalKeySelect(entity string, mapping *Mapping) string { + nk := mapping.NaturalKey() + criteria := "" + for i, field := range nk { + if i > 0 { + criteria += " AND " + } + + var column string + if field.IsScalar() { + column = field.Config.Get("join") + } else { + column = mapping.FieldColumnName(field.Name) + } + + criteria += fmt.Sprintf("%s = ?", column) + } + + table := entityTable(entity) + for _, field := range mapping.ScalarFields() { + join := field.Config.Get("join") + right := strings.Split(join, ".")[0] + via := entityTable(entity) + if field.Config.Get("via") != "" { + via = entityTable(field.Config.Get("via")) + } + table += fmt.Sprintf(" JOIN %s ON %s.%s_id = %s.id", right, via, lex.Singular(right), right) + } + + sql := fmt.Sprintf(stmts["id"], entityTable(entity), table, criteria) + + return sql +} + // Output a line of code that registers the given statement and declares the // associated statement code global variable. func (s *Stmt) register(buf *file.Buffer, sql string, filters ...string) { From 6451a292bd71d0739a565e95638b488e90c42d4e Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Tue, 19 May 2020 12:04:28 +0100 Subject: [PATCH 4/8] lxd/db: Generate delete stements for profile config and devices Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/db/profiles.go | 2 ++ lxd/db/profiles.mapper.go | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/lxd/db/profiles.go b/lxd/db/profiles.go index 19e97787c2..8bd37c96b5 100644 --- a/lxd/db/profiles.go +++ b/lxd/db/profiles.go @@ -37,6 +37,8 @@ import ( //go:generate mapper stmt -p db -e profile create-devices-ref //go:generate mapper stmt -p db -e profile rename //go:generate mapper stmt -p db -e profile delete +//go:generate mapper stmt -p db -e profile delete-config-ref +//go:generate mapper stmt -p db -e profile delete-devices-ref // //go:generate mapper method -p db -e profile URIs //go:generate mapper method -p db -e profile List diff --git a/lxd/db/profiles.mapper.go b/lxd/db/profiles.mapper.go index f71d742c42..df5c752a63 100644 --- a/lxd/db/profiles.mapper.go +++ b/lxd/db/profiles.mapper.go @@ -119,6 +119,14 @@ var profileDelete = cluster.RegisterStmt(` DELETE FROM profiles WHERE project_id = (SELECT projects.id FROM projects WHERE projects.name = ?) AND name = ? `) +var profileDeleteConfigRef = cluster.RegisterStmt(` +DELETE FROM profiles_config WHERE profile_id = ? +`) + +var profileDeleteDevicesRef = cluster.RegisterStmt(` +DELETE FROM profiles_devices WHERE profile_id = ? +`) + // GetProfileURIs returns all available profile URIs. func (c *ClusterTx) GetProfileURIs(filter ProfileFilter) ([]string, error) { // Check which filter criteria are active. From b5ee104c37eb5c692f30d3ab8a28cc321bdc7859 Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Tue, 19 May 2020 12:24:33 +0100 Subject: [PATCH 5/8] shared/generate/db: update statement: take ID instead of natural key Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/db/projects.go | 12 ++++++------ lxd/db/projects.mapper.go | 2 +- shared/generate/db/stmt.go | 21 +-------------------- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/lxd/db/projects.go b/lxd/db/projects.go index 49457c1533..295ec8fde1 100644 --- a/lxd/db/projects.go +++ b/lxd/db/projects.go @@ -132,8 +132,13 @@ func (c *ClusterTx) ProjectHasImages(name string) (bool, error) { // UpdateProject updates the project matching the given key parameters. func (c *ClusterTx) UpdateProject(name string, object api.ProjectPut) error { + id, err := c.GetProjectID(name) + if err != nil { + return errors.Wrap(err, "Fetch project ID") + } + stmt := c.stmt(projectUpdate) - result, err := stmt.Exec(object.Description, name) + result, err := stmt.Exec(object.Description, id) if err != nil { return errors.Wrap(err, "Update project") } @@ -146,11 +151,6 @@ func (c *ClusterTx) UpdateProject(name string, object api.ProjectPut) error { return fmt.Errorf("Query updated %d rows instead of 1", n) } - id, err := c.GetProjectID(name) - if err != nil { - return errors.Wrap(err, "Fetch project ID") - } - // Clear config. _, err = c.tx.Exec(` DELETE FROM projects_config WHERE projects_config.project_id = ? diff --git a/lxd/db/projects.mapper.go b/lxd/db/projects.mapper.go index 2e8fd787e6..3b763721f3 100644 --- a/lxd/db/projects.mapper.go +++ b/lxd/db/projects.mapper.go @@ -77,7 +77,7 @@ UPDATE projects SET name = ? WHERE name = ? var projectUpdate = cluster.RegisterStmt(` UPDATE projects SET description = ? - WHERE name = ? + WHERE id = ? `) var projectDelete = cluster.RegisterStmt(` diff --git a/shared/generate/db/stmt.go b/shared/generate/db/stmt.go index 227733a655..db28faad47 100644 --- a/shared/generate/db/stmt.go +++ b/shared/generate/db/stmt.go @@ -492,28 +492,9 @@ func (s *Stmt) update(buf *file.Buffer) error { } } - mapping, err = Parse(s.packages[s.pkg], lex.Capital(s.entity)) - if err != nil { - return errors.Wrap(err, "Parse entity struct") - } - - nk := mapping.NaturalKey() - where := make([]string, len(nk)) - - for i, field := range nk { - if field.IsScalar() { - ref := lex.Snake(field.Name) - where[i] = fmt.Sprintf("%s_id = (SELECT id FROM %s WHERE name = ?)", ref, lex.Plural(ref)) - } else { - - where[i] = fmt.Sprintf("%s = ?", field.Column()) - } - - } - sql := fmt.Sprintf( stmts[s.kind], entityTable(s.entity), - strings.Join(updates, ", "), strings.Join(where, ", ")) + strings.Join(updates, ", "), "id = ?") s.register(buf, sql) return nil From 4f4e9c8773706d045a85496fa2425b07ee112f67 Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Tue, 19 May 2020 12:49:12 +0100 Subject: [PATCH 6/8] shared/generate/db: Handle config and devices in Update method Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- shared/generate/db/method.go | 69 +++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/shared/generate/db/method.go b/shared/generate/db/method.go index 0ddc903cd9..c0f6859aa0 100644 --- a/shared/generate/db/method.go +++ b/shared/generate/db/method.go @@ -811,8 +811,14 @@ func (m *Method) update(buf *file.Buffer) error { params[i] = fmt.Sprintf("object.%s", field.Name) } + //buf.L("id, err := c.Get%s(%s)", lex.Camel(m.entity), FieldArgs(nk)) + buf.L("id, err := c.Get%sID(%s)", lex.Camel(m.entity), FieldParams(nk)) + buf.L("if err != nil {") + buf.L(" return errors.Wrap(err, \"Get %s\")", m.entity) + buf.L("}") + buf.N() buf.L("stmt := c.stmt(%s)", stmtCodeVar(m.entity, "update")) - buf.L("result, err := stmt.Exec(%s)", strings.Join(params, ", ")+", "+FieldParams(nk)) + buf.L("result, err := stmt.Exec(%s)", strings.Join(params, ", ")+", id") buf.L("if err != nil {") buf.L(" return errors.Wrap(err, \"Update %s\")", m.entity) buf.L("}") @@ -825,6 +831,67 @@ func (m *Method) update(buf *file.Buffer) error { buf.L(" return fmt.Errorf(\"Query updated %%d rows instead of 1\", n)") buf.L("}") buf.N() + + fields = mapping.RefFields() + for _, field := range fields { + switch field.Type.Name { + case "map[string]string": + buf.L("// Delete current config. ") + buf.L("stmt = c.stmt(%s)", stmtCodeVar(m.entity, "deleteConfigRef")) + buf.L("_, err = stmt.Exec(id)") + buf.L("if err != nil {") + buf.L(" return errors.Wrap(err, \"Delete current config\")") + buf.L("}") + buf.N() + buf.L("// Insert config reference. ") + buf.L("stmt = c.stmt(%s)", stmtCodeVar(m.entity, "createConfigRef")) + buf.L("for key, value := range object.%s {", field.Name) + buf.L(" _, err := stmt.Exec(id, key, value)") + buf.L(" if err != nil {") + buf.L(" return errors.Wrap(err, \"Insert config for %s\")", m.entity) + buf.L(" }") + buf.L("}") + buf.N() + case "map[string]map[string]string": + buf.L("// Delete current devices. ") + buf.L("stmt = c.stmt(%s)", stmtCodeVar(m.entity, "deleteDevicesRef")) + buf.L("_, err = stmt.Exec(id)") + buf.L("if err != nil {") + buf.L(" return errors.Wrap(err, \"Delete current devices\")") + buf.L("}") + buf.N() + buf.N() + buf.L("// Insert devices reference. ") + buf.L("for name, config := range object.%s {", field.Name) + buf.L(" typ, ok := config[\"type\"]") + buf.L(" if !ok {") + buf.L(" return fmt.Errorf(\"No type for device %%s\", name)") + buf.L(" }") + buf.L(" typCode, err := dbDeviceTypeToInt(typ)") + buf.L(" if err != nil {") + buf.L(" return errors.Wrapf(err, \"Device type code for %%s\", typ)") + buf.L(" }") + buf.L(" stmt = c.stmt(%s)", stmtCodeVar(m.entity, "createDevicesRef")) + buf.L(" result, err := stmt.Exec(id, name, typCode)") + buf.L(" if err != nil {") + buf.L(" return errors.Wrapf(err, \"Insert device %%s\", name)") + buf.L(" }") + buf.L(" deviceID, err := result.LastInsertId()") + buf.L(" if err != nil {") + buf.L(" return errors.Wrap(err, \"Failed to fetch device ID\")") + buf.L(" }") + buf.L(" stmt = c.stmt(%s)", stmtCodeVar(m.entity, "createDevicesConfigRef")) + buf.L(" for key, value := range config {") + buf.L(" _, err := stmt.Exec(deviceID, key, value)") + buf.L(" if err != nil {") + buf.L(" return errors.Wrap(err, \"Insert config for %s\")", m.entity) + buf.L(" }") + buf.L(" }") + buf.L("}") + buf.N() + } + } + buf.L("return nil") return nil From 3215afdffe7d8ada49cf5057d8ef2ca6615a466f Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Tue, 19 May 2020 12:49:16 +0100 Subject: [PATCH 7/8] lxd/db: Generate Update method for profiles Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/db/profiles.go | 2 + lxd/db/profiles.mapper.go | 81 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/lxd/db/profiles.go b/lxd/db/profiles.go index 8bd37c96b5..b83ad849f8 100644 --- a/lxd/db/profiles.go +++ b/lxd/db/profiles.go @@ -39,6 +39,7 @@ import ( //go:generate mapper stmt -p db -e profile delete //go:generate mapper stmt -p db -e profile delete-config-ref //go:generate mapper stmt -p db -e profile delete-devices-ref +//go:generate mapper stmt -p db -e profile update struct=Profile // //go:generate mapper method -p db -e profile URIs //go:generate mapper method -p db -e profile List @@ -51,6 +52,7 @@ import ( //go:generate mapper method -p db -e profile Create struct=Profile //go:generate mapper method -p db -e profile Rename //go:generate mapper method -p db -e profile Delete +//go:generate mapper method -p db -e profile Update struct=Profile // Profile is a value object holding db-related details about a profile. type Profile struct { diff --git a/lxd/db/profiles.mapper.go b/lxd/db/profiles.mapper.go index df5c752a63..c9970eb9b4 100644 --- a/lxd/db/profiles.mapper.go +++ b/lxd/db/profiles.mapper.go @@ -127,6 +127,12 @@ var profileDeleteDevicesRef = cluster.RegisterStmt(` DELETE FROM profiles_devices WHERE profile_id = ? `) +var profileUpdate = cluster.RegisterStmt(` +UPDATE profiles + SET project_id = (SELECT id FROM projects WHERE name = ?), name = ?, description = ? + WHERE id = ? +`) + // GetProfileURIs returns all available profile URIs. func (c *ClusterTx) GetProfileURIs(filter ProfileFilter) ([]string, error) { // Check which filter criteria are active. @@ -715,3 +721,78 @@ func (c *ClusterTx) DeleteProfile(project string, name string) error { return nil } + +// UpdateProfile updates the profile matching the given key parameters. +func (c *ClusterTx) UpdateProfile(project string, name string, object Profile) error { + id, err := c.GetProfileID(project, name) + if err != nil { + return errors.Wrap(err, "Get profile") + } + + stmt := c.stmt(profileUpdate) + result, err := stmt.Exec(object.Project, object.Name, object.Description, id) + if err != nil { + return errors.Wrap(err, "Update profile") + } + + n, err := result.RowsAffected() + if err != nil { + return errors.Wrap(err, "Fetch affected rows") + } + if n != 1 { + return fmt.Errorf("Query updated %d rows instead of 1", n) + } + + // Delete current config. + stmt = c.stmt(profileDeleteConfigRef) + _, err = stmt.Exec(id) + if err != nil { + return errors.Wrap(err, "Delete current config") + } + + // Insert config reference. + stmt = c.stmt(profileCreateConfigRef) + for key, value := range object.Config { + _, err := stmt.Exec(id, key, value) + if err != nil { + return errors.Wrap(err, "Insert config for profile") + } + } + + // Delete current devices. + stmt = c.stmt(profileDeleteDevicesRef) + _, err = stmt.Exec(id) + if err != nil { + return errors.Wrap(err, "Delete current devices") + } + + // Insert devices reference. + for name, config := range object.Devices { + typ, ok := config["type"] + if !ok { + return fmt.Errorf("No type for device %s", name) + } + typCode, err := dbDeviceTypeToInt(typ) + if err != nil { + return errors.Wrapf(err, "Device type code for %s", typ) + } + stmt = c.stmt(profileCreateDevicesRef) + result, err := stmt.Exec(id, name, typCode) + if err != nil { + return errors.Wrapf(err, "Insert device %s", name) + } + deviceID, err := result.LastInsertId() + if err != nil { + return errors.Wrap(err, "Failed to fetch device ID") + } + stmt = c.stmt(profileCreateDevicesConfigRef) + for key, value := range config { + _, err := stmt.Exec(deviceID, key, value) + if err != nil { + return errors.Wrap(err, "Insert config for profile") + } + } + } + + return nil +} From 94b74aa66d2010f5657621b5611566d071f159a4 Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <free.ekanay...@canonical.com> Date: Tue, 19 May 2020 13:04:08 +0100 Subject: [PATCH 8/8] lxd: Plug new UpdateProfile() db method into doProfileUpdate Signed-off-by: Free Ekanayaka <free.ekanay...@canonical.com> --- lxd/profiles_utils.go | 57 ++++++------------------------------------- 1 file changed, 8 insertions(+), 49 deletions(-) diff --git a/lxd/profiles_utils.go b/lxd/profiles_utils.go index 4728c55601..672d584d10 100644 --- a/lxd/profiles_utils.go +++ b/lxd/profiles_utils.go @@ -2,10 +2,8 @@ package main import ( "fmt" - "reflect" "github.com/lxc/lxd/lxd/db" - "github.com/lxc/lxd/lxd/db/query" deviceConfig "github.com/lxc/lxd/lxd/device/config" "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" @@ -78,53 +76,14 @@ func doProfileUpdate(d *Daemon, project, name string, id int64, profile *api.Pro } // Update the database - err = query.Retry(func() error { - tx, err := d.cluster.Begin() - if err != nil { - return err - } - - if profile.Description != req.Description { - err = db.UpdateProfileDescription(tx, id, req.Description) - if err != nil { - tx.Rollback() - return err - } - } - - // Optimize for description-only changes - if reflect.DeepEqual(profile.Config, req.Config) && reflect.DeepEqual(profile.Devices, req.Devices) { - err = db.TxCommit(tx) - if err != nil { - return err - } - - return nil - } - - err = db.ClearProfileConfig(tx, id) - if err != nil { - tx.Rollback() - return err - } - - err = db.CreateProfileConfig(tx, id, req.Config) - if err != nil { - tx.Rollback() - return err - } - - err = db.AddDevicesToEntity(tx, "profile", id, deviceConfig.NewDevices(req.Devices)) - if err != nil { - tx.Rollback() - return err - } - - err = db.TxCommit(tx) - if err != nil { - return err - } - return nil + err = d.cluster.Transaction(func(tx *db.ClusterTx) error { + return tx.UpdateProfile(project, name, db.Profile{ + Project: project, + Name: name, + Description: req.Description, + Config: req.Config, + Devices: req.Devices, + }) }) if err != nil { return err
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel