func createV50()

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
}