func PutConfigurationResponse()

in traffic_ops/traffic_ops_golang/cdni/shared.go [318:457]


func PutConfigurationResponse(w http.ResponseWriter, r *http.Request) {
	inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"approved", "id"}, []string{"id"})
	if userErr != nil || sysErr != nil {
		api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
		return
	}
	defer inf.Close()

	reqId := inf.IntParams["id"]
	approvedString := inf.Params["approved"]
	approved, err := strconv.ParseBool(approvedString)
	if err != nil {
		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, errors.New("approved parameter must be a boolean"), nil)
		return
	}

	db, err := api.GetDB(r.Context())
	if err != nil {
		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("getting async db: %w", err))
		return
	}

	logTx, err := db.Begin()
	if err != nil {
		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("getting log tx: %w", err))
		return
	}
	defer logTx.Commit()

	rows, err := inf.Tx.Tx.Query(SelectCapabilityUpdateQuery, reqId)
	if err != nil {
		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("querying for capability update request: %w", err))
		return
	}
	defer log.Close(rows, "closing capabilities update query")
	var ucdn string
	var data json.RawMessage
	var host string
	var asyncId int
	var requestType string
	count := 0
	for rows.Next() {
		if err := rows.Scan(&ucdn, &data, &asyncId, &requestType, &host); err != nil {
			api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("scanning db rows: %w", err))
			return
		}
		count++
	}
	if count == 0 {
		api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, fmt.Errorf("no configuration request for that id"), nil)
		return
	}

	if !approved {
		if asyncErr := api.UpdateAsyncStatus(db, api.AsyncFailed, "Requested configuration update has been denied.", asyncId, true); asyncErr != nil {
			log.Errorf("updating async status for id %d: %s", asyncId, asyncErr.Error())
		}
		status, err := deleteCapabilityRequest(reqId, inf.Tx.Tx)
		if err != nil {
			api.HandleErr(w, r, inf.Tx.Tx, status, nil, fmt.Errorf("deleting configuration request from queue: %w", err))
			return
		}
		msg := "Successfully denied configuration update request."
		api.CreateChangeLogRawTx(api.ApiChange, msg, inf.User, inf.Tx.Tx)
		api.WriteResp(w, r, msg)
		return
	}

	var updatedDataList []GenericMetadata
	if err = json.Unmarshal(data, &updatedDataList); err != nil {
		api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("unmarshalling data for configuration update: %w", err))
		return
	}

	var unsupportedTypes []string
	for _, updatedData := range updatedDataList {
		if !updatedData.Type.isValid() {
			unsupportedTypes = append(unsupportedTypes, string(updatedData.Type))
		}
	}

	if len(unsupportedTypes) != 0 {
		api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, fmt.Errorf("unsupported generic metadata types found: %v", strings.Join(unsupportedTypes, ", ")), nil)
		return
	}

	for _, updatedData := range updatedDataList {
		switch updatedData.Type {
		case MiRequestedCapacityLimits:
			var capacityRequestedLimits CapacityRequestedLimits
			if err = json.Unmarshal(updatedData.Value, &capacityRequestedLimits); err != nil {
				api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("unmarshalling data for configuration update: %w", err))
				return
			}
			for _, capLim := range capacityRequestedLimits.RequestedLimits {
				capId, err := getCapabilityIdFromFootprints(capLim, ucdn, inf)
				if err != nil {
					api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("finding capability for given information: %w", err))
					return
				}

				query := UpdateLimitsByCapabilityAndLimitTypeQuery
				queryParams := []interface{}{capLim.LimitValue, capId, capLim.LimitType}
				if host != "" {
					query = query + " AND $4 = ANY(scope_value)"
					queryParams = []interface{}{capLim.LimitValue, capId, capLim.LimitType, host}
				}

				result, err := inf.Tx.Tx.Exec(query, queryParams...)
				if err != nil {
					api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("updating capacity: %w", err))
					return
				}

				if rowsAffected, err := result.RowsAffected(); err != nil {
					api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("updating capacity: getting rows affected: %w", err))
					return
				} else if rowsAffected < 1 {
					api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, fmt.Errorf("no capacity found for update: host: %s, type: %s, limit: %v", host, updatedData.Type, capLim), nil)
					return
				} else if rowsAffected > 1 {
					api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("capacity update affected too many rows: %d", rowsAffected))
					return
				}
			}
		}
	}

	if asyncErr := api.UpdateAsyncStatus(db, api.AsyncSucceeded, "Capacity requested update has been completed.", asyncId, true); asyncErr != nil {
		log.Errorf("updating async status for id %v: %v", asyncId, asyncErr)
	}
	status, err := deleteCapabilityRequest(reqId, inf.Tx.Tx)
	if err != nil {
		api.HandleErr(w, r, inf.Tx.Tx, status, nil, fmt.Errorf("deleting capacity request from queue: %w", err))
		return
	}
	msg := "Successfully updated configuration."
	api.CreateChangeLogRawTx(api.ApiChange, msg, inf.User, logTx)
	api.WriteResp(w, r, msg)
}