rawlinp commented on a change in pull request #4700:
URL: https://github.com/apache/trafficcontrol/pull/4700#discussion_r434221600



##########
File path: traffic_ops/traffic_ops_golang/server/servers.go
##########
@@ -359,267 +757,475 @@ WHERE s.id IN (` + edgeIDs + `)))
        return mids, nil, nil, http.StatusOK
 }
 
-func (s *TOServer) Update() (error, error, int) {
-       if s.IP6Address != nil && len(strings.TrimSpace(*s.IP6Address)) == 0 {
-               s.IP6Address = nil
-       }
-       // see if type changed
-       typeID := -1
-       // see if cdn changed
-       cdnId := -1
-
-       if err := s.APIInfo().Tx.QueryRow("SELECT type, cdn_id FROM server 
WHERE id = $1", s.ID).Scan(&typeID, &cdnId); err != nil {
+func checkTypeChangeSafety(server tc.CommonServerProperties, tx *sqlx.Tx) 
(error, error, int) {
+       // see if cdn or type changed
+       var cdnID int
+       var typeID int
+       if err := tx.QueryRow("SELECT type, cdn_id FROM server WHERE id = $1", 
*server.ID).Scan(&typeID, &cdnID); err != nil {
                if err == sql.ErrNoRows {
-                       return errors.New("no server found with this id"), nil, 
http.StatusNotFound
+                       return errors.New("no server found with this ID"), nil, 
http.StatusNotFound
                }
                return nil, fmt.Errorf("getting current server type: %v", err), 
http.StatusInternalServerError
        }
 
-       dsIDs := []int64{}
-       if err := s.APIInfo().Tx.QueryRowx("SELECT ARRAY(SELECT deliveryservice 
FROM deliveryservice_server WHERE server = $1)", s.ID).Scan(pq.Array(&dsIDs)); 
err != nil && err != sql.ErrNoRows {
+       var dsIDs []int64
+       if err := tx.QueryRowx("SELECT ARRAY(SELECT deliveryservice FROM 
deliveryservice_server WHERE server = $1)", server.ID).Scan(pq.Array(&dsIDs)); 
err != nil && err != sql.ErrNoRows {
                return nil, fmt.Errorf("getting server assigned delivery 
services: %v", err), http.StatusInternalServerError
        }
+       // If type is changing ensure it isn't assigned to any DSes.
+       if typeID != *server.TypeID {
+               if len(dsIDs) != 0 {
+                       return errors.New("server type can not be updated when 
it is currently assigned to Delivery Services"), nil, http.StatusConflict
+               }
+       }
        // Check to see if the user is trying to change the CDN of a server, 
which is already linked with a DS
-       if cdnId != *s.CDNID && len(dsIDs) != 0 {
+       if cdnID != *server.CDNID && len(dsIDs) != 0 {
                return errors.New("server cdn can not be updated when it is 
currently assigned to delivery services"), nil, http.StatusConflict
        }
-       // If type is changing ensure it isn't assigned to any DSes.
-       if typeID != *s.TypeID {
-               if len(dsIDs) != 0 {
-                       return errors.New("server type can not be updated when 
it is currently assigned to delivery services"), nil, http.StatusConflict
+
+       return nil, nil, http.StatusOK
+}
+
+func createInterfaces(id int, interfaces []tc.ServerInterfaceInfo, tx *sql.Tx) 
(error, error, int) {
+       ifaceQry := `
+       INSERT INTO interface (
+               max_bandwidth,
+               monitor,
+               mtu,
+               name,
+               server
+       ) VALUES
+       `
+       ipQry := `
+       INSERT INTO ip_address (
+               address,
+               gateway,
+               interface,
+               server,
+               service_address
+       ) VALUES
+       `
+
+       ifaceQueryParts := make([]string, 0, len(interfaces))
+       ipQueryParts := make([]string, 0, len(interfaces))
+       ifaceArgs := make([]interface{}, 0, len(interfaces))
+       ipArgs := make([]interface{}, 0, len(interfaces))
+       for i, iface := range interfaces {
+               argStart := i * 5
+               ifaceQueryParts = append(ifaceQueryParts, fmt.Sprintf("($%d, 
$%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, 
argStart+5))
+               ifaceArgs = append(ifaceArgs, iface.MaxBandwidth, 
iface.Monitor, iface.MTU, iface.Name, id)
+               for _, ip := range iface.IPAddresses {
+                       argStart = len(ipArgs)
+                       ipQueryParts = append(ipQueryParts, fmt.Sprintf("($%d, 
$%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, 
argStart+5))
+                       ipArgs = append(ipArgs, ip.Address, ip.Gateway, 
iface.Name, id, ip.ServiceAddress)
                }
        }
 
-       current := TOServer{}
-       err := s.ReqInfo.Tx.QueryRowx(selectV20UpdatesQuery()+` WHERE 
sv.id=$1`, strconv.Itoa(*s.ID)).StructScan(&current)
+       ifaceQry += strings.Join(ifaceQueryParts, ",")
+       log.Debugf("Inserting interfaces for new server, query is: %s", 
ifaceQry)
+
+       _, err := tx.Exec(ifaceQry, ifaceArgs...)
        if err != nil {
                return api.ParseDBError(err)
        }
-       defaultIsService := true
-       if s.IPIsService == nil {
-               if current.IPIsService != nil {
-                       s.IPIsService = current.IPIsService
-               } else {
-                       s.IPIsService = &defaultIsService
+
+       ipQry += strings.Join(ipQueryParts, ",")
+       log.Debugf("Inserting IP addresses for new server, query is: %s", ipQry)
+
+       _, err = tx.Exec(ipQry, ipArgs...)
+       if err != nil {
+               return api.ParseDBError(err)
+       }
+
+       return nil, nil, http.StatusOK
+}
+
+func deleteInterfaces(id int, tx *sql.Tx) (error, error, int) {
+       if _, err := tx.Exec(deleteIPsQuery, id); err != nil && err != 
sql.ErrNoRows {
+               return api.ParseDBError(err)
+       }
+
+       if _, err := tx.Exec(deleteInterfacesQuery, id); err != nil && err != 
sql.ErrNoRows {
+               return api.ParseDBError(err)
+       }
+
+       return nil, nil, http.StatusOK
+}
+
+func Update(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id"}, 
[]string{"id"})
+       tx := inf.Tx.Tx
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       var server tc.ServerNullableV2
+       var interfaces []tc.ServerInterfaceInfo
+       if inf.Version.Major >= 3 {
+               var newServer tc.ServerNullable
+               if err := json.NewDecoder(r.Body).Decode(&newServer); err != 
nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+                       return
+               }
+               serviceInterface, err := validateV3(newServer, tx)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+                       return
+               }
+
+               server, err = newServer.ToServerV2()
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, fmt.Errorf("converting v3 server to v2 for update: %v", err))
+                       return
+               }
+               server.InterfaceName = util.StrPtr(serviceInterface)
+               interfaces = newServer.Interfaces
+       } else if inf.Version.Major == 2 {
+               if err := json.NewDecoder(r.Body).Decode(&server); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+                       return
+               }
+
+               err := validateV2(&server, tx)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+                       return
+               }
+
+               interfaces, err = 
server.LegacyInterfaceDetails.ToInterfaces(*server.IPIsService, 
*server.IP6IsService)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, fmt.Errorf("converting server legacy interfaces to interface array: %v", 
err))
+                       return
+               }
+       } else {
+               var legacyServer tc.ServerNullableV11
+               if err := json.NewDecoder(r.Body).Decode(&legacyServer); err != 
nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+                       return
+               }
+
+               err := validateV1(legacyServer, tx)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+                       return
+               }
+
+               interfaces, err = 
legacyServer.LegacyInterfaceDetails.ToInterfaces(true, true)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, fmt.Errorf("converting server legacy interfaces to interface array: %v", 
err))
+                       return
+               }
+               server = tc.ServerNullableV2{
+                       ServerNullableV11: legacyServer,
+                       IPIsService:       util.BoolPtr(true),
+                       IP6IsService:      util.BoolPtr(true),
                }
        }
-       if s.IP6IsService == nil {
-               if current.IP6IsService != nil {
-                       s.IP6IsService = current.IP6IsService
-               } else {
-                       s.IP6IsService = &defaultIsService
+
+       server.ID = new(int)
+       *server.ID = inf.IntParams["id"]
+
+       if userErr, sysErr, errCode = 
checkTypeChangeSafety(server.CommonServerProperties, inf.Tx); userErr != nil || 
sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       rows, err := inf.Tx.NamedQuery(updateQuery, server)
+       if err != nil {
+               userErr, sysErr, errCode = api.ParseDBError(err)
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+       defer rows.Close()
+
+       rowsAffected := 0
+       for rows.Next() {
+               if err := rows.StructScan(&server); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusNotFound, nil, 
fmt.Errorf("scanning lastUpdated from server insert: %v", err))
+                       return
                }
+               rowsAffected++
        }
 
-       return api.GenericUpdate(s)
+       if rowsAffected < 1 {
+               api.HandleErr(w, r, tx, http.StatusNotFound, errors.New("no 
server found with this id"), nil)
+               return
+       }
+       if rowsAffected > 1 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
fmt.Errorf("update for server #%d affected too many rows (%d)", *server.ID, 
rowsAffected))
+               return
+       }
+
+       if userErr, sysErr, errCode = deleteInterfaces(inf.IntParams["id"], 
tx); userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       if userErr, sysErr, errCode = createInterfaces(inf.IntParams["id"], 
interfaces, tx); userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       if inf.Version.Major >= 3 {
+               api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", 
tc.ServerNullable{CommonServerProperties: server.CommonServerProperties, 
Interfaces: interfaces})
+       } else if inf.Version.Minor <= 1 {
+               api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", 
server.ServerNullableV11)
+       } else {
+               api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", 
server)
+       }
+
+       changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: updated", 
*server.HostName, *server.DomainName, *server.ID)
+       api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx)
 }
 
-func (s *TOServer) Create() (error, error, int) {
-       // TODO put in Validate()
-       if s.IP6Address != nil && len(strings.TrimSpace(*s.IP6Address)) == 0 {
-               s.IP6Address = nil
+func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) {
+       var server tc.ServerNullableV11
+
+       tx := inf.Tx.Tx
+
+       if err := json.NewDecoder(r.Body).Decode(&server); err != nil {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+               return
        }
-       if s.XMPPID == nil || *s.XMPPID == "" {
-               hostName := *s.HostName
-               s.XMPPID = &hostName
+
+       if err := validateV1(server, tx); err != nil {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+               return
        }
 
-       // default the is service field to true if omitted and to upgrade 
version < 1.4
-       defaultIsService := true
-       if s.IPIsService == nil {
-               s.IPIsService = &defaultIsService
+       resultRows, err := inf.Tx.NamedQuery(insertQuery, server)
+       if err != nil {
+               userErr, sysErr, errCode := api.ParseDBError(err)
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
        }
-       if s.IP6IsService == nil {
-               s.IP6IsService = &defaultIsService
+       defer resultRows.Close()
+
+       rowsAffected := 0
+       for resultRows.Next() {
+               rowsAffected++
+               if err := 
resultRows.StructScan(&server.CommonServerProperties); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, fmt.Errorf("server create scanning: %v", err))
+                       return
+               }
+       }
+       if rowsAffected == 0 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("server create: no server was inserted, no id was returned"))
+               return
+       } else if rowsAffected > 1 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("too many ids returned from server insert"))
        }
 
-       return api.GenericCreate(s)
-}
+       ifaces, err := server.LegacyInterfaceDetails.ToInterfaces(true, true)
+       if err != nil {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
err)
+       }
 
-func (s *TOServer) Delete() (error, error, int) { return api.GenericDelete(s) }
+       if userErr, sysErr, errCode := createInterfaces(*server.ID, ifaces, 
tx); err != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created")
+       api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server)
 
-func selectV20UpdatesQuery() string {
-       return `SELECT 
-sv.ip_address_is_service, 
-sv.ip6_address_is_service 
-FROM 
-       server sv`
+       changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: created", 
*server.HostName, *server.DomainName, *server.ID)
+       api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx)
 }
 
-func selectQuery() string {
-       const JumboFrameBPS = 9000
-       return `SELECT
-cg.name as cachegroup,
-s.cachegroup as cachegroup_id,
-s.cdn_id,
-cdn.name as cdn_name,
-s.domain_name,
-s.guid,
-s.host_name,
-s.https_port,
-s.id,
-s.ilo_ip_address,
-s.ilo_ip_gateway,
-s.ilo_ip_netmask,
-s.ilo_password,
-s.ilo_username,
-COALESCE(s.interface_mtu, ` + strconv.Itoa(JumboFrameBPS) + `) as 
interface_mtu,
-s.interface_name,
-s.ip6_address,
-s.ip6_address_is_service,
-s.ip6_gateway,
-s.ip_address,
-s.ip_address_is_service,
-s.ip_gateway,
-s.ip_netmask,
-s.last_updated,
-s.mgmt_ip_address,
-s.mgmt_ip_gateway,
-s.mgmt_ip_netmask,
-s.offline_reason,
-pl.name as phys_location,
-s.phys_location as phys_location_id,
-p.name as profile,
-p.description as profile_desc,
-s.profile as profile_id,
-s.rack,
-s.reval_pending,
-s.router_host_name,
-s.router_port_name,
-st.name as status,
-s.status as status_id,
-s.tcp_port,
-t.name as server_type,
-s.type as server_type_id,
-s.upd_pending as upd_pending,
-s.xmpp_id,
-s.xmpp_passwd
-FROM
-  server s
-JOIN cachegroup cg ON s.cachegroup = cg.id
-JOIN cdn cdn ON s.cdn_id = cdn.id
-JOIN phys_location pl ON s.phys_location = pl.id
-JOIN profile p ON s.profile = p.id
-JOIN status st ON s.status = st.id
-JOIN type t ON s.type = t.id`
+func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) {
+       var server tc.ServerNullableV2
+
+       tx := inf.Tx.Tx
+
+       if err := json.NewDecoder(r.Body).Decode(&server); err != nil {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+               return
+       }
+
+       if err := validateV2(&server, tx); err != nil {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+               return
+       }
+
+       resultRows, err := inf.Tx.NamedQuery(insertQuery, server)
+       if err != nil {
+               userErr, sysErr, errCode := api.ParseDBError(err)
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+       defer resultRows.Close()
+
+       rowsAffected := 0
+       for resultRows.Next() {
+               rowsAffected++
+               if err := 
resultRows.StructScan(&server.CommonServerProperties); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, fmt.Errorf("server create scanning: %v", err))
+                       return
+               }
+       }
+       if rowsAffected == 0 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("server create: no server was inserted, no id was returned"))
+               return
+       } else if rowsAffected > 1 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("too many ids returned from server insert"))
+       }
+
+       ifaces, err := 
server.LegacyInterfaceDetails.ToInterfaces(*server.IPIsService, 
*server.IP6IsService)
+       if err != nil {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
err)
+       }
+
+       if userErr, sysErr, errCode := createInterfaces(*server.ID, ifaces, 
tx); err != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created")
+       api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server)
+
+       changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: created", 
*server.HostName, *server.DomainName, *server.ID)
+       api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx)
 }
 
-func insertQuery() string {
-       query := `INSERT INTO server (
-cachegroup,
-cdn_id,
-domain_name,
-host_name,
-https_port,
-ilo_ip_address,
-ilo_ip_netmask,
-ilo_ip_gateway,
-ilo_username,
-ilo_password,
-interface_mtu,
-interface_name,
-ip6_address,
-ip6_address_is_service,
-ip6_gateway,
-ip_address,
-ip_address_is_service,
-ip_netmask,
-ip_gateway,
-mgmt_ip_address,
-mgmt_ip_netmask,
-mgmt_ip_gateway,
-offline_reason,
-phys_location,
-profile,
-rack,
-router_host_name,
-router_port_name,
-status,
-tcp_port,
-type,
-upd_pending,
-xmpp_id,
-xmpp_passwd
-) VALUES (
-:cachegroup_id,
-:cdn_id,
-:domain_name,
-:host_name,
-:https_port,
-:ilo_ip_address,
-:ilo_ip_netmask,
-:ilo_ip_gateway,
-:ilo_username,
-:ilo_password,
-:interface_mtu,
-:interface_name,
-:ip6_address,
-:ip6_address_is_service,
-:ip6_gateway,
-:ip_address,
-:ip_address_is_service,
-:ip_netmask,
-:ip_gateway,
-:mgmt_ip_address,
-:mgmt_ip_netmask,
-:mgmt_ip_gateway,
-:offline_reason,
-:phys_location_id,
-:profile_id,
-:rack,
-:router_host_name,
-:router_port_name,
-:status_id,
-:tcp_port,
-:server_type_id,
-:upd_pending,
-:xmpp_id,
-:xmpp_passwd
-) RETURNING id,last_updated`
-       return query
+func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) {
+       var server tc.ServerNullable
+
+       tx := inf.Tx.Tx
+
+       if err := json.NewDecoder(r.Body).Decode(&server); err != nil {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+               return
+       }
+
+       serviceInterface, err := validateV3(server, tx)
+       if err != nil {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+               return
+       }
+
+       v2Server, err := server.ToServerV2()
+       if err != nil {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
err)
+               return
+       }
+
+       v2Server.InterfaceName = &serviceInterface
+
+       resultRows, err := inf.Tx.NamedQuery(insertQuery, v2Server)
+       if err != nil {
+               userErr, sysErr, errCode := api.ParseDBError(err)
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+       defer resultRows.Close()
+
+       rowsAffected := 0
+       for resultRows.Next() {
+               rowsAffected++
+               if err := 
resultRows.StructScan(&server.CommonServerProperties); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, fmt.Errorf("server create scanning: %v", err))
+                       return
+               }
+       }
+       if rowsAffected == 0 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("server create: no server was inserted, no id was returned"))
+               return
+       } else if rowsAffected > 1 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("too many ids returned from server insert"))
+               return
+       }
+
+       userErr, sysErr, errCode := createInterfaces(*server.ID, 
server.Interfaces, tx)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created")
+       api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server)
+
+       changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: created", 
*server.HostName, *server.DomainName, *server.ID)
+       api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx)
 }
 
-func updateQuery() string {
-       query := `UPDATE
-server SET
-cachegroup=:cachegroup_id,
-cdn_id=:cdn_id,
-domain_name=:domain_name,
-host_name=:host_name,
-https_port=:https_port,
-ilo_ip_address=:ilo_ip_address,
-ilo_ip_netmask=:ilo_ip_netmask,
-ilo_ip_gateway=:ilo_ip_gateway,
-ilo_username=:ilo_username,
-ilo_password=:ilo_password,
-interface_mtu=:interface_mtu,
-interface_name=:interface_name,
-ip6_address=:ip6_address,
-ip6_address_is_service=:ip6_address_is_service,
-ip6_gateway=:ip6_gateway,
-ip_address=:ip_address,
-ip_address_is_service=:ip_address_is_service,
-ip_netmask=:ip_netmask,
-ip_gateway=:ip_gateway,
-mgmt_ip_address=:mgmt_ip_address,
-mgmt_ip_netmask=:mgmt_ip_netmask,
-mgmt_ip_gateway=:mgmt_ip_gateway,
-offline_reason=:offline_reason,
-phys_location=:phys_location_id,
-profile=:profile_id,
-rack=:rack,
-router_host_name=:router_host_name,
-router_port_name=:router_port_name,
-status=:status_id,
-tcp_port=:tcp_port,
-type=:server_type_id,
-upd_pending=:upd_pending,
-xmpp_id=:xmpp_id,
-xmpp_passwd=:xmpp_passwd
-WHERE id=:id RETURNING last_updated`
-       return query
+func Create(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       switch {
+       case inf.Version.Major <= 1:
+               createV1(inf, w, r)
+       case inf.Version.Major == 2:
+               createV2(inf, w, r)
+       default:
+               createV3(inf, w, r)
+       }
 }
 
-func deleteQuery() string {
-       return `DELETE FROM server WHERE id = :id`
+func Delete(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id"}, 
[]string{"id"})
+       tx := inf.Tx.Tx
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       id := inf.IntParams["id"]
+
+       var servers []tc.ServerNullable
+       servers, _, userErr, sysErr, errCode = 
getServers(map[string]string{"id": inf.Params["id"]}, inf.Tx, inf.User)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       if len(servers) < 1 {
+               api.HandleErr(w, r, tx, http.StatusNotFound, fmt.Errorf("no 
server exists by id #%d", id), nil)
+               return
+       }
+       if len(servers) > 1 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
fmt.Errorf("there are somehow two servers with id %d - cannot delete", id))
+               return
+       }
+
+       userErr, sysErr, errCode = deleteInterfaces(id, tx)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+
+       if err := tx.QueryRow(deleteServerQuery, id).Scan(); err != nil {

Review comment:
       I think this might also need to be an `Exec`, and we might need to 
handle the "no rows" error separately instead of lumping it in with the other 
errors. What did the API do in this case previously? 404? 




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to