in traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go [1004:1310]
func updateV50(w http.ResponseWriter, r *http.Request, inf *api.Info, ds *tc.DeliveryServiceV5, omitExtraLongDescFields bool, longDesc1, longDesc2 *string) (*tc.DeliveryServiceV5, int, error, error) {
tx := inf.Tx.Tx
user := inf.User
userErr, sysErr := Validate(tx, ds)
if userErr != nil {
return nil, http.StatusBadRequest, fmt.Errorf("invalid request: %w", userErr), nil
}
if sysErr != nil {
return nil, http.StatusInternalServerError, nil, sysErr
}
if authorized, err := isTenantAuthorized(inf, ds); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("checking tenant: %w", err)
} else if !authorized {
return nil, http.StatusForbidden, errors.New("not authorized on this tenant"), nil
}
if ds.ID == nil {
return nil, http.StatusBadRequest, errors.New("missing id"), nil
}
dsType, ok, err := getDSType(tx, ds.XMLID)
if !ok {
return nil, http.StatusNotFound, errors.New("delivery service '" + ds.XMLID + "' not found"), nil
}
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("getting delivery service type during update: %w", err)
}
var errCode int
var oldDetails TODeliveryServiceOldDetails
if dsType.HasSSLKeys() {
oldDetails, userErr, sysErr, errCode = getOldDetails(*ds.ID, tx)
if userErr != nil || sysErr != nil {
return nil, errCode, userErr, sysErr
}
sslKeysExist, err := getSSLVersion(ds.XMLID, tx)
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %w", err)
}
if sslKeysExist {
errStr := "delivery service has ssl keys that cannot be automatically changed, therefore %s is immutable"
if oldDetails.OldCDNID != ds.CDNID {
return nil, http.StatusBadRequest, fmt.Errorf(errStr, "CDN ID"), nil
}
if ds.CDNName != nil && oldDetails.OldCDNName != *ds.CDNName {
return nil, http.StatusBadRequest, fmt.Errorf(errStr, "CDN Name"), nil
}
if oldDetails.OldRoutingName != ds.RoutingName {
return nil, http.StatusBadRequest, fmt.Errorf(errStr, "Routing Name"), nil
}
ds.SSLKeyVersion = oldDetails.OldSSLKeyVersion
}
}
// TODO change DeepCachingType to implement sql.Valuer and sql.Scanner, so sqlx struct scan can be used.
deepCachingType := tc.DeepCachingType("").String()
if ds.DeepCachingType != "" {
deepCachingType = ds.DeepCachingType.String() // necessary, because DeepCachingType's default needs to insert the string, not "", and Query doesn't call .String().
}
userErr, sysErr, errCode = api.CheckIfUnModified(r.Header, inf.Tx, *ds.ID, "deliveryservice")
if userErr != nil || sysErr != nil {
return nil, errCode, userErr, sysErr
}
if errCode, userErr, sysErr = dbhelpers.CheckTopology(inf.Tx, *ds); userErr != nil || sysErr != nil {
return nil, errCode, userErr, sysErr
}
if ds.Topology != nil {
if len(ds.RequiredCapabilities) > 0 {
if userErr, sysErr, status := EnsureTopologyBasedRequiredCapabilities(tx, *ds.ID, *ds.Topology, ds.RequiredCapabilities); userErr != nil || sysErr != nil {
return nil, status, userErr, sysErr
}
}
userErr, sysErr, status := dbhelpers.CheckOriginServerInDSCG(tx, *ds.ID, *ds.Topology)
if userErr != nil || sysErr != nil {
return nil, status, userErr, sysErr
}
}
var geoLimitCountries string
if ds.GeoLimitCountries != nil {
geoLimitCountries = strings.Join(ds.GeoLimitCountries, ",")
}
var resultRows *sql.Rows
if omitExtraLongDescFields {
if longDesc1 != nil || longDesc2 != nil {
return nil, http.StatusBadRequest, errors.New("the longDesc1 and longDesc2 fields are no longer supported in API 4.0 onwards"), nil
}
resultRows, err = tx.Query(updateDSQueryWithoutLD1AndLD2(),
ds.Active,
ds.CCRDNSTTL,
ds.CDNID,
ds.CheckPath,
deepCachingType,
ds.DisplayName,
ds.DNSBypassCNAME,
ds.DNSBypassIP,
ds.DNSBypassIP6,
ds.DNSBypassTTL,
ds.DSCP,
ds.EdgeHeaderRewrite,
ds.GeoLimitRedirectURL,
ds.GeoLimit,
geoLimitCountries,
ds.GeoProvider,
ds.GlobalMaxMBPS,
ds.GlobalMaxTPS,
ds.FQPacingRate,
ds.HTTPBypassFQDN,
ds.InfoURL,
ds.InitialDispersion,
ds.IPV6RoutingEnabled,
ds.LogsEnabled,
ds.LongDesc,
ds.MaxDNSAnswers,
ds.MidHeaderRewrite,
ds.MissLat,
ds.MissLong,
ds.MultiSiteOrigin,
ds.OriginShield,
ds.ProfileID,
ds.Protocol,
ds.QStringIgnore,
ds.RangeRequestHandling,
ds.RegexRemap,
ds.Regional,
ds.RegionalGeoBlocking,
ds.RemapText,
ds.RoutingName,
ds.SigningAlgorithm,
ds.SSLKeyVersion,
ds.TenantID,
ds.TRRequestHeaders,
ds.TRResponseHeaders,
ds.TypeID,
ds.XMLID,
ds.AnonymousBlockingEnabled,
ds.ConsistentHashRegex,
ds.MaxOriginConnections,
ds.EcsEnabled,
ds.RangeSliceBlockSize,
ds.Topology,
ds.FirstHeaderRewrite,
ds.InnerHeaderRewrite,
ds.LastHeaderRewrite,
ds.ServiceCategory,
ds.MaxRequestHeaderBytes,
pq.Array(ds.RequiredCapabilities),
ds.ID,
)
} else {
resultRows, err = tx.Query(updateDSQuery(),
ds.Active,
ds.CCRDNSTTL,
ds.CDNID,
ds.CheckPath,
deepCachingType,
ds.DisplayName,
ds.DNSBypassCNAME,
ds.DNSBypassIP,
ds.DNSBypassIP6,
ds.DNSBypassTTL,
ds.DSCP,
ds.EdgeHeaderRewrite,
ds.GeoLimitRedirectURL,
ds.GeoLimit,
geoLimitCountries,
ds.GeoProvider,
ds.GlobalMaxMBPS,
ds.GlobalMaxTPS,
ds.FQPacingRate,
ds.HTTPBypassFQDN,
ds.InfoURL,
ds.InitialDispersion,
ds.IPV6RoutingEnabled,
ds.LogsEnabled,
ds.LongDesc,
longDesc1,
longDesc2,
ds.MaxDNSAnswers,
ds.MidHeaderRewrite,
ds.MissLat,
ds.MissLong,
ds.MultiSiteOrigin,
ds.OriginShield,
ds.ProfileID,
ds.Protocol,
ds.QStringIgnore,
ds.RangeRequestHandling,
ds.RegexRemap,
ds.Regional,
ds.RegionalGeoBlocking,
ds.RemapText,
ds.RoutingName,
ds.SigningAlgorithm,
ds.SSLKeyVersion,
ds.TenantID,
ds.TRRequestHeaders,
ds.TRResponseHeaders,
ds.TypeID,
ds.XMLID,
ds.AnonymousBlockingEnabled,
ds.ConsistentHashRegex,
ds.MaxOriginConnections,
ds.EcsEnabled,
ds.RangeSliceBlockSize,
ds.Topology,
ds.FirstHeaderRewrite,
ds.InnerHeaderRewrite,
ds.LastHeaderRewrite,
ds.ServiceCategory,
ds.MaxRequestHeaderBytes,
pq.Array(ds.RequiredCapabilities),
ds.ID,
)
}
if err != nil {
usrErr, sysErr, code := api.ParseDBError(err)
return nil, code, usrErr, sysErr
}
defer log.Close(resultRows, "updating Delivery Service")
if !resultRows.Next() {
return nil, http.StatusNotFound, errors.New("no delivery service found with this id"), nil
}
var lastUpdated time.Time
if err := resultRows.Scan(&lastUpdated); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("scan updating delivery service: %w", err)
}
if resultRows.Next() {
return nil, http.StatusInternalServerError, nil, errors.New("updating delivery service " + ds.XMLID + ": this update affected too many rows: > 1")
}
if ds.ID == nil {
return nil, http.StatusInternalServerError, nil, errors.New("missing id after update")
}
if len(ds.TLSVersions) < 1 {
ds.TLSVersions = nil
}
err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx)
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("updating TLS versions for DS #%d: %w", *ds.ID, err)
}
newDSType, err := getTypeFromID(ds.TypeID, tx)
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("getting delivery service type after update: %w", err)
}
ds.Type = (*string)(&newDSType)
cdnDomain, err := getCDNDomain(*ds.ID, tx) // need to get the domain again, in case it changed.
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("getting CDN domain: (%s) after update: %w", cdnDomain, err)
}
matchLists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx)
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("getting matchlists after update: %w", err)
}
ml, ok := matchLists[ds.XMLID]
if !ok {
return nil, http.StatusInternalServerError, nil, errors.New("no matchlists after update")
}
ds.MatchList = ml
if err := EnsureParams(tx, *ds.ID, ds.XMLID, ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.SigningAlgorithm, newDSType, ds.MaxOriginConnections); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("ensuring ds parameters: %w", err)
}
if oldDetails.OldOrgServerFQDN != nil && ds.OrgServerFQDN != nil && *oldDetails.OldOrgServerFQDN != *ds.OrgServerFQDN {
if err := updatePrimaryOrigin(tx, user, *ds); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("updating delivery service: %w", err)
}
}
ds.LastUpdated = lastUpdated
// the update may change or delete the query params -- delete existing and re-add if any provided
q := `DELETE FROM deliveryservice_consistent_hash_query_param WHERE deliveryservice_id = $1`
if res, err := tx.Exec(q, *ds.ID); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("deleting consistent hash query params for ds %s: %w", ds.XMLID, err)
} else if c, _ := res.RowsAffected(); c > 0 {
api.CreateChangeLogRawTx(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Deleted "+strconv.FormatInt(c, 10)+" consistent hash query params", user, tx)
}
if _, err = createConsistentHashQueryParams(tx, *ds.ID, ds.ConsistentHashQueryParams); err != nil {
usrErr, sysErr, code := api.ParseDBError(err)
return nil, code, usrErr, sysErr
}
if err := api.CreateChangeLogRawErr(api.ApiChange, "Updated ds: "+ds.XMLID+" id: "+strconv.Itoa(*ds.ID), user, tx); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("writing change log entry: %w", err)
}
if inf.Config.TrafficVaultEnabled && ds.Protocol != nil && (*ds.Protocol == tc.DSProtocolHTTPS || *ds.Protocol == tc.DSProtocolHTTPAndHTTPS || *ds.Protocol == tc.DSProtocolHTTPToHTTPS) {
err, errCode := GeneratePlaceholderSelfSignedCert(*ds, inf, r.Context())
if err != nil || errCode != http.StatusOK {
return nil, errCode, nil, fmt.Errorf("creating self signed default cert: %w", err)
}
}
return ds, http.StatusOK, nil, nil
}