in traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go [380:636]
func createV50(w http.ResponseWriter, r *http.Request, inf *api.Info, ds tc.DeliveryServiceV5, omitExtraLongDescFields bool, longDesc1, longDesc2 *string) (*tc.DeliveryServiceV5, int, error, error) {
var err error
tx := inf.Tx.Tx
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
}
// 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().
}
if errCode, userErr, sysErr := dbhelpers.CheckTopology(inf.Tx, ds); userErr != nil || sysErr != nil {
return nil, errCode, userErr, sysErr
}
userErr, sysErr, errCode := dbhelpers.CheckIfCurrentUserCanModifyCDNWithID(inf.Tx.Tx, int64(ds.CDNID), inf.User.UserName)
if userErr != nil || sysErr != nil {
return nil, errCode, userErr, sysErr
}
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(insertQueryWithoutLD1AndLD2(),
ds.Active,
ds.AnonymousBlockingEnabled,
ds.CCRDNSTTL,
ds.CDNID,
ds.CheckPath,
ds.ConsistentHashRegex,
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.MaxOriginConnections,
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.Topology,
ds.TRRequestHeaders,
ds.TRResponseHeaders,
ds.TypeID,
ds.XMLID,
ds.EcsEnabled,
ds.RangeSliceBlockSize,
ds.FirstHeaderRewrite,
ds.InnerHeaderRewrite,
ds.LastHeaderRewrite,
ds.ServiceCategory,
ds.MaxRequestHeaderBytes,
pq.Array(ds.RequiredCapabilities),
)
} else {
resultRows, err = tx.Query(insertQuery(),
ds.Active,
ds.AnonymousBlockingEnabled,
ds.CCRDNSTTL,
ds.CDNID,
ds.CheckPath,
ds.ConsistentHashRegex,
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.MaxOriginConnections,
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.Topology,
ds.TRRequestHeaders,
ds.TRResponseHeaders,
ds.TypeID,
ds.XMLID,
ds.EcsEnabled,
ds.RangeSliceBlockSize,
ds.FirstHeaderRewrite,
ds.InnerHeaderRewrite,
ds.LastHeaderRewrite,
ds.ServiceCategory,
ds.MaxRequestHeaderBytes,
pq.Array(ds.RequiredCapabilities),
)
}
if err != nil {
usrErr, sysErr, code := api.ParseDBError(err)
return nil, code, usrErr, sysErr
}
defer log.Close(resultRows, "inserting Delivery Service")
id := 0
if !resultRows.Next() {
return nil, http.StatusInternalServerError, nil, errors.New("no deliveryservice request inserted, no id was returned")
}
var lastUpdated time.Time
if err := resultRows.Scan(&id, &lastUpdated); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("could not scan id from insert: %w", err)
}
if resultRows.Next() {
return nil, http.StatusInternalServerError, nil, errors.New("too many ids returned from deliveryservice request insert")
}
ds.ID = &id
if ds.ID == nil {
return nil, http.StatusInternalServerError, nil, errors.New("missing id after insert")
}
dsType, err := getTypeFromID(ds.TypeID, tx)
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("getting delivery service type: %w", err)
}
ds.Type = (*string)(&dsType)
if len(ds.TLSVersions) < 1 {
ds.TLSVersions = nil
} else if err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("creating TLS versions for new Delivery Service: %w", err)
}
if err := createDefaultRegex(tx, *ds.ID, ds.XMLID); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("creating default regex: %w", err)
}
if _, err := createConsistentHashQueryParams(tx, *ds.ID, ds.ConsistentHashQueryParams); err != nil {
usrErr, sysErr, code := api.ParseDBError(err)
return nil, code, usrErr, sysErr
}
matchlists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx)
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("creating DS: reading matchlists: %w", err)
}
matchlist, ok := matchlists[ds.XMLID]
if !ok {
return nil, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: not found")
}
ds.MatchList = matchlist
cdnName, cdnDomain, dnssecEnabled, err := getCDNNameDomainDNSSecEnabled(*ds.ID, tx)
if err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("creating DS: getting CDN info: %w", err)
}
ds.ExampleURLs = MakeExampleURLs(ds.Protocol, tc.DSType(*ds.Type), ds.RoutingName, ds.MatchList, cdnDomain)
if err := EnsureParams(tx, *ds.ID, ds.XMLID, ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.SigningAlgorithm, dsType, ds.MaxOriginConnections); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("ensuring ds parameters: %w", err)
}
if dnssecEnabled && tc.DSType(*ds.Type).UsesDNSSECKeys() {
if !inf.Config.TrafficVaultEnabled {
return nil, http.StatusInternalServerError, nil, errors.New("cannot create DNSSEC keys for delivery service: Traffic Vault is not configured")
}
if userErr, sysErr, statusCode := PutDNSSecKeys(tx, ds.XMLID, cdnName, ds.ExampleURLs, inf.Vault, r.Context()); userErr != nil || sysErr != nil {
return nil, statusCode, userErr, sysErr
}
}
user := inf.User
if err := createPrimaryOrigin(tx, user, ds); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("creating delivery service: %w", err)
}
ds.LastUpdated = lastUpdated
if err := api.CreateChangeLogRawErr(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Created delivery service", user, tx); err != nil {
return nil, http.StatusInternalServerError, nil, fmt.Errorf("error writing to audit log: %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
}