From 47700fe9a164b845d8a779d3f18344dd4135d18b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 25 May 2021 09:09:30 -0600 Subject: [PATCH 01/34] Add migration for DS TLS versions --- .../2021061100000000_ds_tls_versions.sql | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 traffic_ops/app/db/migrations/2021061100000000_ds_tls_versions.sql diff --git a/traffic_ops/app/db/migrations/2021061100000000_ds_tls_versions.sql b/traffic_ops/app/db/migrations/2021061100000000_ds_tls_versions.sql new file mode 100644 index 0000000000..a1c40de70c --- /dev/null +++ b/traffic_ops/app/db/migrations/2021061100000000_ds_tls_versions.sql @@ -0,0 +1,91 @@ +-- syntax:postgresql +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +-- +goose Up +CREATE TABLE IF NOT EXISTS public.deliveryservice_tls_version ( + deliveryservice bigint NOT NULL REFERENCES public.deliveryservice(id) ON DELETE CASCADE ON UPDATE CASCADE, + tls_version text NOT NULL CHECK (tls_version <> ''), + PRIMARY KEY (deliveryservice, tls_version) +); + +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION update_ds_timestamp_on_insert() + RETURNS trigger + AS $$ +BEGIN + UPDATE public.deliveryservice + SET last_updated=now() + WHERE id IN ( + SELECT deliveryservice + FROM new_table + ); + RETURN NULL; +END; +$$ LANGUAGE plpgsql; +-- +goose StatementEnd + +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION update_ds_timestamp_on_delete() + RETURNS trigger + AS $$ +BEGIN + UPDATE public.deliveryservice + SET last_updated=now() + WHERE id IN ( + SELECT deliveryservice + FROM old_table + ); + RETURN NULL; +END; +$$ LANGUAGE plpgsql; +-- +goose StatementEnd + +CREATE TRIGGER update_ds_timestamp_on_tls_version_insertion + AFTER INSERT ON public.deliveryservice_tls_version + REFERENCING NEW TABLE AS new_table + FOR EACH STATEMENT EXECUTE PROCEDURE update_ds_timestamp_on_insert(); + +CREATE TRIGGER update_ds_timestamp_on_tls_version_delete + AFTER DELETE ON public.deliveryservice_tls_version + REFERENCING OLD TABLE AS old_table + FOR EACH STATEMENT EXECUTE PROCEDURE update_ds_timestamp_on_delete(); + +UPDATE public.deliveryservice_request +SET + deliveryservice = jsonb_set(deliveryservice, '{tlsVersions}', 'null') +WHERE + deliveryservice IS NOT NULL; +UPDATE public.deliveryservice_request +SET + original = jsonb_set(original, '{tlsVersions}', 'null') +WHERE + original IS NOT NULL; + +-- +goose Down +UPDATE public.deliveryservice_request +SET + deliveryservice = deliveryservice - 'tlsVersions' +WHERE + deliveryservice IS NOT NULL; + +UPDATE public.deliveryservice_request +SET + original = original - 'tlsVersions' +WHERE + original IS NOT NULL; + +DROP TRIGGER IF EXISTS update_ds_timestamp_on_tls_version_insertion_or_update ON public.deliveryservice_tls_version; +DROP TRIGGER IF EXISTS update_ds_timestamp_on_tls_version_delete ON public.deliveryservice_tls_version; +DROP TABLE IF EXISTS public.deliveryservice_tls_version; +DROP FUNCTION IF EXISTS update_ds_timestamp_on_insert; +DROP FUNCTION IF EXISTS update_ds_timestamp_on_delete; From ace12cfcebebeeb3ce577849ab454366bc0ff176 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 25 May 2021 09:47:23 -0600 Subject: [PATCH 02/34] Update DS model in APIv4 --- .../cdn-in-a-box/enroller/enroller.go | 4 +- lib/go-tc/deliveryservice_requests.go | 16 +- lib/go-tc/deliveryservice_requests_test.go | 5 +- lib/go-tc/deliveryservices.go | 548 +++++++++++++- lib/go-tc/deliveryservices_test.go | 677 ++++++++++++++++++ .../v4/cachegroupsdeliveryservices_test.go | 8 +- .../deliveryservice_request_comments_test.go | 12 +- .../api/v4/deliveryservice_requests_test.go | 93 ++- .../testing/api/v4/deliveryservices_test.go | 409 ++++------- .../api/v4/deliveryserviceservers_test.go | 23 +- .../testing/api/v4/federations_test.go | 4 +- traffic_ops/testing/api/v4/jobs_test.go | 15 +- traffic_ops/testing/api/v4/servers_test.go | 6 +- ...vers_to_deliveryservice_assignment_test.go | 11 +- traffic_ops/testing/api/v4/tenants_test.go | 17 +- .../api/v4/topologies_queue_update_test.go | 6 +- traffic_ops/testing/api/v4/topologies_test.go | 8 +- .../dbhelpers/db_helpers.go | 4 +- .../deliveryservice/deliveryservices.go | 159 ++-- .../deliveryservice/request/requests.go | 12 +- .../deliveryservice/request/validate.go | 2 +- .../deliveryservice/safe.go | 2 +- .../deliveryservice/servers/delete.go | 17 +- traffic_ops/v4-client/deliveryservice.go | 20 +- .../v4-client/deliveryservice_requests.go | 12 +- 25 files changed, 1520 insertions(+), 570 deletions(-) create mode 100644 lib/go-tc/deliveryservices_test.go diff --git a/infrastructure/cdn-in-a-box/enroller/enroller.go b/infrastructure/cdn-in-a-box/enroller/enroller.go index 47769e1a6c..8f091d5e7f 100644 --- a/infrastructure/cdn-in-a-box/enroller/enroller.go +++ b/infrastructure/cdn-in-a-box/enroller/enroller.go @@ -227,7 +227,7 @@ func enrollDeliveryService(toSession *session, r io.Reader) error { if err != nil { for _, alert := range alerts.Alerts.Alerts { if strings.Contains(alert.Text, "already exists") { - log.Infof("Delivery Service '%s' already exists", *s.XMLID) + log.Infof("Delivery Service '%s' already exists", s.XMLID) return nil } } @@ -827,7 +827,7 @@ func enrollFederation(toSession *session, r io.Reader) error { return err } deliveryService := deliveryServices.Response[0] - if deliveryService.CDNName == nil || deliveryService.ID == nil || deliveryService.XMLID == nil { + if deliveryService.CDNName == nil || deliveryService.ID == nil { err = fmt.Errorf("Delivery Service '%s' as returned from Traffic Ops had null or undefined CDN name and/or ID", xmlID) log.Infoln(err) return err diff --git a/lib/go-tc/deliveryservice_requests.go b/lib/go-tc/deliveryservice_requests.go index c1bab3d4a7..b48e30531f 100644 --- a/lib/go-tc/deliveryservice_requests.go +++ b/lib/go-tc/deliveryservice_requests.go @@ -798,12 +798,12 @@ func (dsr DeliveryServiceRequestV40) Downgrade() DeliveryServiceRequestNullable if dsr.XMLID != "" { downgraded.XMLID = new(string) *downgraded.XMLID = dsr.XMLID - } else if dsr.Original != nil && dsr.Original.XMLID != nil { + } else if dsr.Original != nil { downgraded.XMLID = new(string) - *downgraded.XMLID = *dsr.Original.XMLID - } else if dsr.Requested.XMLID != nil { + *downgraded.XMLID = dsr.Original.XMLID + } else { downgraded.XMLID = new(string) - *downgraded.XMLID = *dsr.Requested.XMLID + *downgraded.XMLID = dsr.Requested.XMLID } return downgraded } @@ -870,13 +870,13 @@ func (dsr *DeliveryServiceRequestV40) SetXMLID() { return } - if dsr.ChangeType == DSRChangeTypeDelete && dsr.Original != nil && dsr.Original.XMLID != nil { - dsr.XMLID = *dsr.Original.XMLID + if dsr.ChangeType == DSRChangeTypeDelete && dsr.Original != nil { + dsr.XMLID = dsr.Original.XMLID return } - if dsr.Requested != nil && dsr.Requested.XMLID != nil { - dsr.XMLID = *dsr.Requested.XMLID + if dsr.Requested != nil { + dsr.XMLID = dsr.Requested.XMLID } } diff --git a/lib/go-tc/deliveryservice_requests_test.go b/lib/go-tc/deliveryservice_requests_test.go index 2a6b00d07f..2441439074 100644 --- a/lib/go-tc/deliveryservice_requests_test.go +++ b/lib/go-tc/deliveryservice_requests_test.go @@ -151,7 +151,7 @@ func TestDeliveryServiceRequestV40_Downgrade(t *testing.T) { Requested: &DeliveryServiceV4{}, Status: RequestStatusComplete, } - dsr.Requested.XMLID = &xmlid + dsr.Requested.XMLID = xmlid downgraded := dsr.Downgrade() if downgraded.Assignee != nil { @@ -214,8 +214,7 @@ func ExampleDeliveryServiceRequestV40_SetXMLID() { fmt.Println(dsr.XMLID == "") dsr.Requested = new(DeliveryServiceV4) - dsr.Requested.XMLID = new(string) - *dsr.Requested.XMLID = "test" + dsr.Requested.XMLID = "test" dsr.SetXMLID() fmt.Println(dsr.XMLID) diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go index 662eb611a5..c54fa05a40 100644 --- a/lib/go-tc/deliveryservices.go +++ b/lib/go-tc/deliveryservices.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "time" "github.com/apache/trafficcontrol/lib/go-util" ) @@ -192,12 +193,290 @@ type DeliveryServiceFieldsV31 struct { // DeliveryServiceV40 is a Delivery Service as it appears in version 4.0 of the // Traffic Ops API. type DeliveryServiceV40 struct { - DeliveryServiceFieldsV31 - DeliveryServiceFieldsV30 - DeliveryServiceFieldsV15 - DeliveryServiceFieldsV14 - DeliveryServiceFieldsV13 - DeliveryServiceNullableFieldsV11 + // Active dictates whether the Delivery Service is routed by Traffic Router. + Active bool `json:"active" db:"active"` + // AnonymousBlockingEnabled sets whether or not anonymized IP addresses + // (e.g. Tor exit nodes) should be restricted from accessing the Delivery + // Service's content. + AnonymousBlockingEnabled bool `json:"anonymousBlockingEnabled" db:"anonymous_blocking_enabled"` + // CCRDNSTTL sets the Time-to-Live - in seconds - for DNS responses for this + // Delivery Service from Traffic Router. + CCRDNSTTL *int `json:"ccrDnsTtl" db:"ccr_dns_ttl"` + // CDNID is the integral, unique identifier for the CDN to which the + // Delivery Service belongs. + CDNID int `json:"cdnId" db:"cdn_id"` + // CDNName is the name of the CDN to which the Delivery Service belongs. + CDNName *string `json:"cdnName"` + // CheckPath is a path which may be requested of the Delivery Service's + // origin to ensure it's working properly. + CheckPath *string `json:"checkPath" db:"check_path"` + // ConsistentHashQueryParams is a list of al of the query string parameters + // which ought to be considered by Traffic Router in client request URIs for + // HTTP-routed Delivery Services in the hashing process. + ConsistentHashQueryParams []string `json:"consistentHashQueryParams"` + // ConsistentHashRegex is used by Traffic Router to extract meaningful parts + // of a client's request URI for HTTP-routed Delivery Services before + // hashing the request to find a cache server to which to direct the client. + ConsistentHashRegex *string `json:"consistentHashRegex"` + // DeepCachingType may only legally point to 'ALWAYS' or 'NEVER', which + // define whether "deep caching" may or may not be used for this Delivery + // Service, respectively. + DeepCachingType DeepCachingType `json:"deepCachingType" db:"deep_caching_type"` + // DisplayName is a human-friendly name that might be used in some UIs + // somewhere. + DisplayName string `json:"displayName" db:"display_name"` + // DNSBypassCNAME is a fully qualified domain name to be used in a CNAME + // record presented to clients in bypass scenarios. + DNSBypassCNAME *string `json:"dnsBypassCname" db:"dns_bypass_cname"` + // DNSBypassIP is an IPv4 address to be used in an A record presented to + // clients in bypass scenarios. + DNSBypassIP *string `json:"dnsBypassIp" db:"dns_bypass_ip"` + // DNSBypassIP6 is an IPv6 address to be used in an AAAA record presented to + // clients in bypass scenarios. + DNSBypassIP6 *string `json:"dnsBypassIp6" db:"dns_bypass_ip6"` + // DNSBypassTTL sets the Time-to-Live - in seconds - of DNS responses from + // the Traffic Router that contain records for bypass destinations. + DNSBypassTTL *int `json:"dnsBypassTtl" db:"dns_bypass_ttl"` + // DSCP sets the Differentiated Services Code Point for IP packets + // transferred between clients, origins, and cache servers when obtaining + // and serving content for this Delivery Service. + // See Also: https://en.wikipedia.org/wiki/Differentiated_services + DSCP int `json:"dscp" db:"dscp"` + // EcsEnabled describes whether or not the Traffic Router's EDNS0 Client + // Subnet extensions should be enabled when serving DNS responses for this + // Delivery Service. Even if this is true, the Traffic Router may still + // have the extensions unilaterally disabled in its own configuration. + EcsEnabled bool `json:"ecsEnabled" db:"ecs_enabled"` + // EdgeHeaderRewrite is a "header rewrite rule" used by ATS at the Edge-tier + // of caching. This has no effect on Delivery Services that don't use a + // Topology. + EdgeHeaderRewrite *string `json:"edgeHeaderRewrite" db:"edge_header_rewrite"` + // ExampleURLs is a list of all of the URLs from which content may be + // requested from the Delivery Service. + ExampleURLs []string `json:"exampleURLs"` + // FirstHeaderRewrite is a "header rewrite rule" used by ATS at the first + // caching layer encountered in the Delivery Service's Topology, or nil if + // there is no such rule. This has no effect on Delivery Services that don't + // employ Topologies. + FirstHeaderRewrite *string `json:"firstHeaderRewrite" db:"first_header_rewrite"` + // FQPacingRate sets the maximum bytes per second a cache server will deliver + // on any single TCP connection for this Delivery Service. This may never + // legally point to a value less than zero. + FQPacingRate *int `json:"fqPacingRate" db:"fq_pacing_rate"` + // GeoLimit defines whether or not access to a Delivery Service's content + // should be limited based on the requesting client's geographic location. + // Despite that this is a pointer to an arbitrary integer, the only valid + // values are 0 (which indicates that content should not be limited + // geographically), 1 (which indicates that content should only be served to + // clients whose IP addresses can be found within a Coverage Zone File), and + // 2 (which indicates that content should be served to clients whose IP + // addresses can be found within a Coverage Zone File OR are allowed access + // according to the "array" in GeoLimitCountries). + GeoLimit int `json:"geoLimit" db:"geo_limit"` + // GeoLimitCountries is an "array" of "country codes" that itemizes the + // countries within which the Delivery Service's content ought to be made + // available. This has no effect if GeoLimit is not a pointer to exactly the + // value 2. + GeoLimitCountries *string `json:"geoLimitCountries" db:"geo_limit_countries"` + // GeoLimitRedirectURL is a URL to which clients will be redirected if their + // access to the Delivery Service's content is blocked by GeoLimit rules. + GeoLimitRedirectURL *string `json:"geoLimitRedirectURL" db:"geolimit_redirect_url"` + // GeoProvider names the type of database to be used for providing IP + // address-to-geographic-location mapping for this Delivery Service. The + // only valid values to which it may point are 0 (which indicates the use of + // a MaxMind GeoIP2 database) and 1 (which indicates the use of a Neustar + // GeoPoint IP address database). + GeoProvider int `json:"geoProvider" db:"geo_provider"` + // GlobalMaxMBPS defines a maximum number of MegaBytes Per Second which may + // be served for the Delivery Service before redirecting clients to bypass + // locations. + GlobalMaxMBPS *int `json:"globalMaxMbps" db:"global_max_mbps"` + // GlobalMaxTPS defines a maximum number of Transactions Per Second which + // may be served for the Delivery Service before redirecting clients to + // bypass locations. + GlobalMaxTPS *int `json:"globalMaxTps" db:"global_max_tps"` + // HTTPBypassFQDN is a network location to which clients will be redirected + // in bypass scenarios using HTTP "Location" headers and appropriate + // redirection response codes. + HTTPBypassFQDN *string `json:"httpBypassFqdn" db:"http_bypass_fqdn"` + // ID is an integral, unique identifier for the Delivery Service. + ID *int `json:"id" db:"id"` + // InfoURL is a URL to which operators or clients may be directed to obtain + // further information about a Delivery Service. + InfoURL *string `json:"infoUrl" db:"info_url"` + // InitialDispersion sets the number of cache servers within the first + // caching layer ("Edge-tier" in a non-Topology context) across which + // content will be dispersed per Cache Group. + InitialDispersion *int `json:"initialDispersion" db:"initial_dispersion"` + // InnerHeaderRewrite is a "header rewrite rule" used by ATS at all caching + // layers encountered in the Delivery Service's Topology except the first + // and last, or nil if there is no such rule. This has no effect on Delivery + // Services that don't employ Topologies. + InnerHeaderRewrite *string `json:"innerHeaderRewrite" db:"inner_header_rewrite"` + // IPV6RoutingEnabled controls whether or not routing over IPv6 should be + // done for this Delivery Service. + IPV6RoutingEnabled bool `json:"ipv6RoutingEnabled" db:"ipv6_routing_enabled"` + // LastHeaderRewrite is a "header rewrite rule" used by ATS at the first + // caching layer encountered in the Delivery Service's Topology, or nil if + // there is no such rule. This has no effect on Delivery Services that don't + // employ Topologies. + LastHeaderRewrite *string `json:"lastHeaderRewrite" db:"last_header_rewrite"` + // LastUpdated is the time and date at which the Delivery Service was last + // updated. + LastUpdated time.Time `json:"lastUpdated" db:"last_updated"` + // LogsEnabled controls nothing. It is kept only for legacy compatibility. + LogsEnabled bool `json:"logsEnabled" db:"logs_enabled"` + // LongDesc is a description of the Delivery Service, having arbitrary + // length. + LongDesc *string `json:"longDesc" db:"long_desc"` + // LongDesc1 is a description of the Delivery Service, having arbitrary + // length. + LongDesc1 *string `json:"longDesc1" db:"long_desc_1"` + // LongDesc2 is a description of the Delivery Service, having arbitrary + // length. + LongDesc2 *string `json:"longDesc2" db:"long_desc_2"` + // MatchList is a list of Regular Expressions used for routing the Delivery + // Service. Order matters, and the array is not allowed to be sparse. + MatchList []DeliveryServiceMatch `json:"matchList"` + // MaxDNSAnswers sets the maximum number of records which should be returned + // by Traffic Router in DNS responses to requests for resolving names for + // this Delivery Service. + MaxDNSAnswers *int `json:"maxDnsAnswers" db:"max_dns_answers"` + // MaxOriginConnections defines the total maximum number of connections + // that the highest caching layer ("Mid-tier" in a non-Topology context) is + // allowed to have concurrently open to the Delivery Service's Origin. This + // may never legally point to a value less than 0. + MaxOriginConnections *int `json:"maxOriginConnections" db:"max_origin_connections"` + // MaxRequestHeaderBytes is the maximum size (in bytes) of the request + // header that is allowed for this Delivery Service. + MaxRequestHeaderBytes *int `json:"maxRequestHeaderBytes" db:"max_request_header_bytes"` + // MidHeaderRewrite is a "header rewrite rule" used by ATS at the Mid-tier + // of caching. This has no effect on Delivery Services that don't use a + // Topology. + MidHeaderRewrite *string `json:"midHeaderRewrite" db:"mid_header_rewrite"` + // MissLat is a latitude to default to for clients of this Delivery Service + // when geolocation attempts fail. + MissLat *float64 `json:"missLat" db:"miss_lat"` + // MissLong is a longitude to default to for clients of this Delivery + // Service when geolocation attempts fail. + MissLong *float64 `json:"missLong" db:"miss_long"` + // MultiSiteOrigin determines whether or not the Delivery Service makes use + // of "Multi-Site Origin". + MultiSiteOrigin *bool `json:"multiSiteOrigin" db:"multi_site_origin"` + // OriginShield is a field that does nothing. It is kept only for legacy + // compatibility reasons. + OriginShield *string `json:"originShield" db:"origin_shield"` + // OrgServerFQDN is the URL - NOT Fully Qualified Domain Name - of the + // origin of the Delivery Service's content. + OrgServerFQDN *string `json:"orgServerFqdn" db:"org_server_fqdn"` + // ProfileDesc is the Description of the Profile used by the Delivery + // Service, if any. + ProfileDesc *string `json:"profileDescription"` + // ProfileID is the integral, unique identifier of the Profile used by the + // Delivery Service, if any. + ProfileID *int `json:"profileId" db:"profile"` + // ProfileName is the Name of the Profile used by the Delivery Service, if + // any. + ProfileName *string `json:"profileName"` + // Protocol defines the protocols by which caching servers may communicate + // with clients. The valid values to which it may point are 0 (which implies + // that only HTTP may be used), 1 (which implies that only HTTPS may be + // used), 2 (which implies that either HTTP or HTTPS may be used), and 3 + // (which implies that clients using HTTP must be redirected to use HTTPS, + // while communications over HTTPS may proceed as normal). + Protocol *int `json:"protocol" db:"protocol"` + // QStringIgnore sets how query strings in HTTP requests to cache servers + // from clients are treated. The only valid values to which it may point are + // 0 (which implies that all caching layers will pass query strings in + // upstream requests and use them in the cache key), 1 (which implies that + // all caching layers will pass query strings in upstream requests, but not + // use them in cache keys), and 2 (which implies that the first encountered + // caching layer - "Edge-tier" in a non-Topology context - will strip query + // strings, effectively preventing them from being passed in upstream + // requests, and not use them in the cache key). + QStringIgnore *int `json:"qstringIgnore" db:"qstring_ignore"` + // RangeRequestHandling defines how HTTP GET requests with a Range header + // will be handled by cache servers serving the Delivery Service's content. + // The only valid values to which it may point are 0 (which implies that + // Range requests will not be cached at all), 1 (which implies that the + // background_fetch plugin will be used to service the range request while + // caching the whole object), 2 (which implies that the cache_range_requests + // plugin will be used to cache ranges as unique objects), and 3 (which + // implies that the slice plugin will be used to slice range based requests + // into deterministic chunks.) + RangeRequestHandling *int `json:"rangeRequestHandling" db:"range_request_handling"` + // RangeSliceBlockSize defines the size of range request blocks - or + // "slices" - used by the "slice" plugin. This has no effect if + // RangeRequestHandling does not point to exactly 3. This may never legally + // point to a value less than zero. + RangeSliceBlockSize *int `json:"rangeSliceBlockSize" db:"range_slice_block_size"` + // Regex Remap is a raw line to be inserted into "regex_remap.config" on the + // cache server. Care is necessitated in its use, because the input is in no + // way restricted, validated, or limited in scope to the Delivery Service. + RegexRemap *string `json:"regexRemap" db:"regex_remap"` + // RegionalGeoBlocking defines whether or not whatever Regional Geo Blocking + // rules are configured on the Traffic Router serving content for this + // Delivery Service will have an effect on the traffic of this Delivery + // Service. + RegionalGeoBlocking bool `json:"regionalGeoBlocking" db:"regional_geo_blocking"` + // RemapText is raw text to insert in "remap.config" on the cache servers + // serving content for this Delivery Service. Care is necessitated in its + // use, because the input is in no way restricted, validated, or limited in + // scope to the Delivery Service. + RemapText *string `json:"remapText" db:"remap_text"` + // RoutingName defines the lowest-level DNS label used by the Delivery + // Service, e.g. if trafficcontrol.apache.org were a Delivery Service, it + // would have a RoutingName of "trafficcontrol". + RoutingName string `json:"routingName" db:"routing_name"` + // ServiceCategory defines a category to which a Delivery Service may + // belong, which will cause HTTP Responses containing content for the + // Delivery Service to have the "X-CDN-SVC" header with a value that is the + // XMLID of the Delivery Service. + ServiceCategory *string `json:"serviceCategory" db:"service_category"` + // Signed is a legacy field. It is allowed to be `true` if and only if + // SigningAlgorithm is not nil. + Signed bool `json:"signed"` + // SigningAlgorithm is the name of the algorithm used to sign CDN URIs for + // this Delivery Service's content, or nil if no URI signing is done for the + // Delivery Service. This may only point to the values "url_sig" or + // "uri_signing". + SigningAlgorithm *string `json:"signingAlgorithm" db:"signing_algorithm"` + // SSLKeyVersion incremented whenever Traffic Portal generates new SSL keys + // for the Delivery Service, effectively making it a "generational" marker. + SSLKeyVersion *int `json:"sslKeyVersion" db:"ssl_key_version"` + // Tenant is the Tenant to which the Delivery Service belongs. + Tenant *string `json:"tenant"` + // TenantID is the integral, unique identifier for the Tenant to which the + // Delivery Service belongs. + TenantID int `json:"tenantId" db:"tenant_id"` + // TLSVersions is the list of explicitly supported TLS versions for cache + // servers serving the Delivery Service's content. + TLSVersions []string `json:"tlsVersions" db:"tls_versions"` + // Topology is the name of the Topology used by the Delivery Service, or nil + // if no Topology is used. + Topology *string `json:"topology" db:"topology"` + // TRResponseHeaders is a set of headers (separated by CRLF pairs as per the + // HTTP spec) and their values (separated by a colon as per the HTTP spec) + // which will be sent by Traffic Router in HTTP responses to client requests + // for this Delivery Service's content. This has no effect on DNS-routed or + // un-routed Delivery Service Types. + TRResponseHeaders *string `json:"trResponseHeaders"` + // TRRequestHeaders is an "array" of HTTP headers which should be logged + // from client HTTP requests for this Delivery Service's content by Traffic + // Router, separated by newlines. This has no effect on DNS-routed or + // un-routed Delivery Service Types. + TRRequestHeaders *string `json:"trRequestHeaders"` + // Type describes how content is routed and cached for this Delivery Service + // as well as what other properties have any meaning. + Type *DSType `json:"type"` + // TypeID is an integral, unique identifier for the Tenant to which the + // Delivery Service belongs. + TypeID int `json:"typeId" db:"type"` + // XMLID is a unique identifier that is also the second lowest-level DNS + // label used by the Delivery Service. For example, if a Delivery Service's + // content may be requested from video.demo1.mycdn.ciab.test, it may be + // inferred that the Delivery Service's XMLID is demo1. + XMLID string `json:"xmlId" db:"xml_id"` } // DeliveryServiceV4 is a Delivery Service as it appears in version 4 of the @@ -347,39 +626,238 @@ func (ds *DeliveryServiceV4) RemoveLD1AndLD2() DeliveryServiceV4 { } // DowngradeToV3 converts the 4.x DS to a 3.x DS +// DowngradeToV3 converts the 4.x DS to a 3.x DS. func (ds *DeliveryServiceV4) DowngradeToV3() DeliveryServiceNullableV30 { - return DeliveryServiceNullableV30{ - DeliveryServiceV30: DeliveryServiceV30{ - DeliveryServiceNullableV15: DeliveryServiceNullableV15{ - DeliveryServiceNullableV14: DeliveryServiceNullableV14{ - DeliveryServiceNullableV13: DeliveryServiceNullableV13{ - DeliveryServiceNullableV12: DeliveryServiceNullableV12{ - DeliveryServiceNullableV11: DeliveryServiceNullableV11{ - DeliveryServiceNullableFieldsV11: ds.DeliveryServiceNullableFieldsV11, - }, - }, - DeliveryServiceFieldsV13: ds.DeliveryServiceFieldsV13, - }, - DeliveryServiceFieldsV14: ds.DeliveryServiceFieldsV14, - }, - DeliveryServiceFieldsV15: ds.DeliveryServiceFieldsV15, - }, - DeliveryServiceFieldsV30: ds.DeliveryServiceFieldsV30, - }, - DeliveryServiceFieldsV31: ds.DeliveryServiceFieldsV31, + var ret DeliveryServiceNullableV30 + ret.Active = new(bool) + *ret.Active = ds.Active + ret.AnonymousBlockingEnabled = new(bool) + *ret.AnonymousBlockingEnabled = ds.AnonymousBlockingEnabled + ret.CCRDNSTTL = ds.CCRDNSTTL + ret.CDNID = new(int) + *ret.CDNID = ds.CDNID + ret.CDNName = ds.CDNName + ret.CheckPath = ds.CheckPath + ret.ConsistentHashRegex = ds.ConsistentHashRegex + ret.ConsistentHashQueryParams = make([]string, len(ds.ConsistentHashQueryParams)) + copy(ret.ConsistentHashQueryParams, ds.ConsistentHashQueryParams) + ret.DeepCachingType = new(DeepCachingType) + *ret.DeepCachingType = ds.DeepCachingType + ret.DisplayName = new(string) + *ret.DisplayName = ds.DisplayName + ret.DNSBypassCNAME = ds.DNSBypassCNAME + ret.DNSBypassIP = ds.DNSBypassIP + ret.DNSBypassIP6 = ds.DNSBypassIP6 + ret.DNSBypassTTL = ds.DNSBypassTTL + ret.DSCP = new(int) + *ret.DSCP = ds.DSCP + ret.EcsEnabled = ds.EcsEnabled + ret.EdgeHeaderRewrite = ds.EdgeHeaderRewrite + ret.ExampleURLs = make([]string, len(ds.ExampleURLs)) + copy(ret.ExampleURLs, ds.ExampleURLs) + ret.FirstHeaderRewrite = ds.FirstHeaderRewrite + ret.FQPacingRate = ds.FQPacingRate + ret.GeoLimit = new(int) + *ret.GeoLimit = ds.GeoLimit + ret.GeoLimitCountries = ds.GeoLimitCountries + ret.GeoLimitRedirectURL = ds.GeoLimitRedirectURL + ret.GeoProvider = new(int) + *ret.GeoProvider = ds.GeoProvider + ret.GlobalMaxMBPS = ds.GlobalMaxMBPS + ret.GlobalMaxTPS = ds.GlobalMaxTPS + ret.HTTPBypassFQDN = ds.HTTPBypassFQDN + ret.ID = ds.ID + ret.InfoURL = ds.InfoURL + ret.InitialDispersion = ds.InitialDispersion + ret.InnerHeaderRewrite = ds.InnerHeaderRewrite + ret.IPV6RoutingEnabled = new(bool) + *ret.IPV6RoutingEnabled = ds.IPV6RoutingEnabled + ret.LastHeaderRewrite = ds.LastHeaderRewrite + ret.LastUpdated = TimeNoModFromTime(ds.LastUpdated) + ret.LogsEnabled = new(bool) + *ret.LogsEnabled = ds.LogsEnabled + ret.LongDesc = ds.LongDesc + ret.LongDesc1 = ds.LongDesc1 + ret.LongDesc2 = ds.LongDesc2 + if ds.MatchList != nil { + ret.MatchList = new([]DeliveryServiceMatch) + *ret.MatchList = make([]DeliveryServiceMatch, len(ds.MatchList)) + copy(*ret.MatchList, ds.MatchList) + } else { + ret.MatchList = nil } -} - -// UpgradeToV4 converts the 3.x DS to a 4.x DS + ret.MaxDNSAnswers = ds.MaxDNSAnswers + ret.MaxOriginConnections = ds.MaxOriginConnections + ret.MaxRequestHeaderBytes = ds.MaxRequestHeaderBytes + ret.MidHeaderRewrite = ds.MidHeaderRewrite + ret.MissLat = ds.MissLat + ret.MissLong = ds.MissLong + ret.MultiSiteOrigin = ds.MultiSiteOrigin + ret.OriginShield = ds.OriginShield + ret.OrgServerFQDN = ds.OrgServerFQDN + ret.ProfileDesc = ds.ProfileDesc + ret.ProfileID = ds.ProfileID + ret.ProfileName = ds.ProfileName + ret.Protocol = ds.Protocol + ret.QStringIgnore = ds.QStringIgnore + ret.RangeRequestHandling = ds.RangeRequestHandling + ret.RangeSliceBlockSize = ds.RangeSliceBlockSize + ret.RegexRemap = ds.RegexRemap + ret.RegionalGeoBlocking = new(bool) + *ret.RegionalGeoBlocking = ds.RegionalGeoBlocking + ret.RemapText = ds.RemapText + ret.RoutingName = new(string) + *ret.RoutingName = ds.RoutingName + ret.ServiceCategory = ds.ServiceCategory + ret.Signed = ds.Signed + ret.SigningAlgorithm = ds.SigningAlgorithm + ret.SSLKeyVersion = ds.SSLKeyVersion + ret.Tenant = ds.Tenant + ret.TenantID = new(int) + *ret.TenantID = ds.TenantID + ret.Topology = ds.Topology + ret.TRResponseHeaders = ds.TRResponseHeaders + ret.TRRequestHeaders = ds.TRRequestHeaders + ret.Type = ds.Type + ret.TypeID = new(int) + *ret.TypeID = ds.TypeID + ret.XMLID = new(string) + *ret.XMLID = ds.XMLID + + return ret +} + +// UpgradeToV4 converts the 3.x DS to a 4.x DS. func (ds *DeliveryServiceNullableV30) UpgradeToV4() DeliveryServiceV4 { - return DeliveryServiceV4{ - DeliveryServiceFieldsV31: ds.DeliveryServiceFieldsV31, - DeliveryServiceFieldsV30: ds.DeliveryServiceFieldsV30, - DeliveryServiceFieldsV15: ds.DeliveryServiceFieldsV15, - DeliveryServiceFieldsV14: ds.DeliveryServiceFieldsV14, - DeliveryServiceFieldsV13: ds.DeliveryServiceFieldsV13, - DeliveryServiceNullableFieldsV11: ds.DeliveryServiceNullableFieldsV11, + var ret DeliveryServiceV4 + if ds.Active != nil && *ds.Active { + ret.Active = true + } else { + ret.Active = false + } + if ds.AnonymousBlockingEnabled != nil && *ds.AnonymousBlockingEnabled { + ret.AnonymousBlockingEnabled = true + } else { + ret.AnonymousBlockingEnabled = false + } + ret.CCRDNSTTL = ds.CCRDNSTTL + if ds.CDNID != nil { + ret.CDNID = *ds.CDNID + } + ret.CDNName = ds.CDNName + ret.CheckPath = ds.CheckPath + ret.ConsistentHashRegex = ds.ConsistentHashRegex + ret.ConsistentHashQueryParams = make([]string, len(ds.ConsistentHashQueryParams)) + copy(ret.ConsistentHashQueryParams, ds.ConsistentHashQueryParams) + if ds.DeepCachingType != nil && *ds.DeepCachingType == DeepCachingTypeAlways { + ret.DeepCachingType = DeepCachingTypeAlways + } else { + ret.DeepCachingType = DeepCachingTypeNever + } + if ds.DisplayName != nil { + ret.DisplayName = *ds.DisplayName + } + ret.DNSBypassCNAME = ds.DNSBypassCNAME + ret.DNSBypassIP = ds.DNSBypassIP + ret.DNSBypassIP6 = ds.DNSBypassIP6 + ret.DNSBypassTTL = ds.DNSBypassTTL + if ds.DSCP != nil { + ret.DSCP = *ds.DSCP + } + ret.EcsEnabled = ds.EcsEnabled + ret.EdgeHeaderRewrite = ds.EdgeHeaderRewrite + ret.ExampleURLs = make([]string, len(ds.ExampleURLs)) + copy(ret.ExampleURLs, ds.ExampleURLs) + ret.FirstHeaderRewrite = ds.FirstHeaderRewrite + ret.FQPacingRate = ds.FQPacingRate + if ds.GeoLimit != nil && (*ds.GeoLimit == 1 || *ds.GeoLimit == 2) { + ret.GeoLimit = *ds.GeoLimit + } else { + ret.GeoLimit = 0 + } + ret.GeoLimitCountries = ds.GeoLimitCountries + ret.GeoLimitRedirectURL = ds.GeoLimitRedirectURL + if ds.GeoProvider != nil && *ds.GeoProvider == 1 { + ret.GeoProvider = 1 + } else { + ret.GeoProvider = 0 + } + ret.GlobalMaxMBPS = ds.GlobalMaxMBPS + ret.GlobalMaxTPS = ds.GlobalMaxTPS + ret.HTTPBypassFQDN = ds.HTTPBypassFQDN + ret.ID = ds.ID + ret.InfoURL = ds.InfoURL + ret.InitialDispersion = ds.InitialDispersion + ret.InnerHeaderRewrite = ds.InnerHeaderRewrite + if ds.IPV6RoutingEnabled != nil && *ds.IPV6RoutingEnabled { + ret.IPV6RoutingEnabled = true + } else { + ret.IPV6RoutingEnabled = false + } + ret.LastHeaderRewrite = ds.LastHeaderRewrite + if ds.LastUpdated != nil { + ret.LastUpdated = ds.LastUpdated.Time + } + if ds.LogsEnabled != nil && *ds.LogsEnabled { + ret.LogsEnabled = true + } else { + ret.LogsEnabled = false + } + ret.LongDesc = ds.LongDesc + ret.LongDesc1 = ds.LongDesc1 + ret.LongDesc2 = ds.LongDesc2 + if ds.MatchList != nil { + ret.MatchList = make([]DeliveryServiceMatch, len(*ds.MatchList)) + copy(ret.MatchList, *ds.MatchList) + } else { + ret.MatchList = nil + } + ret.MaxDNSAnswers = ds.MaxDNSAnswers + ret.MaxOriginConnections = ds.MaxOriginConnections + ret.MaxRequestHeaderBytes = ds.MaxRequestHeaderBytes + ret.MidHeaderRewrite = ds.MidHeaderRewrite + ret.MissLat = ds.MissLat + ret.MissLong = ds.MissLong + ret.MultiSiteOrigin = ds.MultiSiteOrigin + ret.OriginShield = ds.OriginShield + ret.OrgServerFQDN = ds.OrgServerFQDN + ret.ProfileDesc = ds.ProfileDesc + ret.ProfileID = ds.ProfileID + ret.ProfileName = ds.ProfileName + ret.Protocol = ds.Protocol + ret.QStringIgnore = ds.QStringIgnore + ret.RangeRequestHandling = ds.RangeRequestHandling + ret.RangeSliceBlockSize = ds.RangeSliceBlockSize + ret.RegexRemap = ds.RegexRemap + if ds.RegionalGeoBlocking != nil && *ds.RegionalGeoBlocking { + ret.RegionalGeoBlocking = true + } else { + ret.RegionalGeoBlocking = false + } + ret.RemapText = ds.RemapText + if ds.RoutingName != nil { + ret.RoutingName = *ds.RoutingName + } + ret.ServiceCategory = ds.ServiceCategory + ret.Signed = ds.Signed + ret.SigningAlgorithm = ds.SigningAlgorithm + ret.SSLKeyVersion = ds.SSLKeyVersion + ret.Tenant = ds.Tenant + if ds.TenantID != nil { + ret.TenantID = *ds.TenantID + } + ret.TLSVersions = nil + ret.Topology = ds.Topology + ret.TRResponseHeaders = ds.TRResponseHeaders + ret.TRRequestHeaders = ds.TRRequestHeaders + ret.Type = ds.Type + if ds.TypeID != nil { + ret.TypeID = *ds.TypeID + } + if ds.XMLID != nil { + ret.XMLID = *ds.XMLID } + return ret } func jsonValue(v interface{}) (driver.Value, error) { diff --git a/lib/go-tc/deliveryservices_test.go b/lib/go-tc/deliveryservices_test.go new file mode 100644 index 0000000000..c4f2791215 --- /dev/null +++ b/lib/go-tc/deliveryservices_test.go @@ -0,0 +1,677 @@ +package tc + +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import "testing" + +func compareV31DSes(a, b DeliveryServiceNullableV30, t *testing.T) { + if (a.Active == nil && b.Active != nil) || (a.Active != nil && b.Active == nil) { + t.Error("Mismatched 'Active' property; one was nil but the other was not.") + } else if a.Active != nil && *a.Active != *b.Active { + t.Errorf("Mismatched 'Active' property; one was '%v', the other was '%v'", *a.Active, *b.Active) + } + if (a.AnonymousBlockingEnabled == nil && b.AnonymousBlockingEnabled != nil) || (a.AnonymousBlockingEnabled != nil && b.AnonymousBlockingEnabled == nil) { + t.Error("Mismatched 'AnonymousBlockingEnabled' property; one was nil but the other was not.") + } else if a.AnonymousBlockingEnabled != nil && *a.AnonymousBlockingEnabled != *b.AnonymousBlockingEnabled { + t.Errorf("Mismatched 'AnonymousBlockingEnabled' property; one was '%v', the other was '%v'", *a.AnonymousBlockingEnabled, *b.AnonymousBlockingEnabled) + } + if (a.CCRDNSTTL == nil && b.CCRDNSTTL != nil) || (a.CCRDNSTTL != nil && b.CCRDNSTTL == nil) { + t.Error("Mismatched 'CCRDNSTTL' property; one was nil but the other was not.") + } else if a.CCRDNSTTL != nil && *a.CCRDNSTTL != *b.CCRDNSTTL { + t.Errorf("Mismatched 'CCRDNSTTL' property; one was '%v', the other was '%v'", *a.CCRDNSTTL, *b.CCRDNSTTL) + } + if (a.CDNID == nil && b.CDNID != nil) || (a.CDNID != nil && b.CDNID == nil) { + t.Error("Mismatched 'CDNID' property; one was nil but the other was not.") + } else if a.CDNID != nil && *a.CDNID != *b.CDNID { + t.Errorf("Mismatched 'CDNID' property; one was '%v', the other was '%v'", *a.CDNID, *b.CDNID) + } + if (a.CDNName == nil && b.CDNName != nil) || (a.CDNName != nil && b.CDNName == nil) { + t.Error("Mismatched 'CDNName' property; one was nil but the other was not.") + } else if a.CDNName != nil && *a.CDNName != *b.CDNName { + t.Errorf("Mismatched 'CDNName' property; one was '%v', the other was '%v'", *a.CDNName, *b.CDNName) + } + if (a.CheckPath == nil && b.CheckPath != nil) || (a.CheckPath != nil && b.CheckPath == nil) { + t.Error("Mismatched 'CheckPath' property; one was nil but the other was not.") + } else if a.CheckPath != nil && *a.CheckPath != *b.CheckPath { + t.Errorf("Mismatched 'CheckPath' property; one was '%v', the other was '%v'", *a.CheckPath, *b.CheckPath) + } + if len(a.ConsistentHashQueryParams) != len(b.ConsistentHashQueryParams) { + t.Errorf("Mismatched 'ConsistentHashQueryParams' property; one contained %d but the other contained %d.", len(a.ConsistentHashQueryParams), len(b.ConsistentHashQueryParams)) + } else { + for i, qp := range a.ConsistentHashQueryParams { + if qp != b.ConsistentHashQueryParams[i] { + t.Errorf("Mismatched 'ConsistentHashQueryParams[%d]'; one was %s, but the other was %s", i, qp, b.ConsistentHashQueryParams[i]) + } + } + } + if (a.ConsistentHashRegex == nil && b.ConsistentHashRegex != nil) || (a.ConsistentHashRegex != nil && b.ConsistentHashRegex == nil) { + t.Error("Mismatched 'ConsistentHashRegex' property; one was nil but the other was not.") + } else if a.ConsistentHashRegex != nil && *a.ConsistentHashRegex != *b.ConsistentHashRegex { + t.Errorf("Mismatched 'ConsistentHashRegex' property; one was '%v', the other was '%v'", *a.ConsistentHashRegex, *b.ConsistentHashRegex) + } + if (a.DeepCachingType == nil && b.DeepCachingType != nil) || (a.DeepCachingType != nil && b.DeepCachingType == nil) { + t.Error("Mismatched 'DeepCachingType' property; one was nil but the other was not.") + } else if a.DeepCachingType != nil && *a.DeepCachingType != *b.DeepCachingType { + t.Errorf("Mismatched 'DeepCachingType' property; one was '%v', the other was '%v'", *a.DeepCachingType, *b.DeepCachingType) + } + if (a.DisplayName == nil && b.DisplayName != nil) || (a.DisplayName != nil && b.DisplayName == nil) { + t.Error("Mismatched 'DisplayName' property; one was nil but the other was not.") + } else if a.DisplayName != nil && *a.DisplayName != *b.DisplayName { + t.Errorf("Mismatched 'DisplayName' property; one was '%v', the other was '%v'", *a.DisplayName, *b.DisplayName) + } + if (a.DNSBypassCNAME == nil && b.DNSBypassCNAME != nil) || (a.DNSBypassCNAME != nil && b.DNSBypassCNAME == nil) { + t.Error("Mismatched 'DNSBypassCNAME' property; one was nil but the other was not.") + } else if a.DNSBypassCNAME != nil && *a.DNSBypassCNAME != *b.DNSBypassCNAME { + t.Errorf("Mismatched 'DNSBypassCNAME' property; one was '%v', the other was '%v'", *a.DNSBypassCNAME, *b.DNSBypassCNAME) + } + if (a.DNSBypassIP6 == nil && b.DNSBypassIP6 != nil) || (a.DNSBypassIP6 != nil && b.DNSBypassIP6 == nil) { + t.Error("Mismatched 'DNSBypassIP6' property; one was nil but the other was not.") + } else if a.DNSBypassIP6 != nil && *a.DNSBypassIP6 != *b.DNSBypassIP6 { + t.Errorf("Mismatched 'DNSBypassIP6' property; one was '%v', the other was '%v'", *a.DNSBypassIP6, *b.DNSBypassIP6) + } + if (a.DNSBypassIP == nil && b.DNSBypassIP != nil) || (a.DNSBypassIP != nil && b.DNSBypassIP == nil) { + t.Error("Mismatched 'DNSBypassIP' property; one was nil but the other was not.") + } else if a.DNSBypassIP != nil && *a.DNSBypassIP != *b.DNSBypassIP { + t.Errorf("Mismatched 'DNSBypassIP' property; one was '%v', the other was '%v'", *a.DNSBypassIP, *b.DNSBypassIP) + } + if (a.DNSBypassTTL == nil && b.DNSBypassTTL != nil) || (a.DNSBypassTTL != nil && b.DNSBypassTTL == nil) { + t.Error("Mismatched 'DNSBypassTTL' property; one was nil but the other was not.") + } else if a.DNSBypassTTL != nil && *a.DNSBypassTTL != *b.DNSBypassTTL { + t.Errorf("Mismatched 'DNSBypassTTL' property; one was '%v', the other was '%v'", *a.DNSBypassTTL, *b.DNSBypassTTL) + } + if (a.DSCP == nil && b.DSCP != nil) || (a.DSCP != nil && b.DSCP == nil) { + t.Error("Mismatched 'DSCP' property; one was nil but the other was not.") + } else if a.DSCP != nil && *a.DSCP != *b.DSCP { + t.Errorf("Mismatched 'DSCP' property; one was '%v', the other was '%v'", *a.DSCP, *b.DSCP) + } + if a.EcsEnabled != b.EcsEnabled { + t.Errorf("Mismatched 'EcsEnabled' property; one was '%v', the other was '%v'", a.EcsEnabled, b.EcsEnabled) + } + if (a.EdgeHeaderRewrite == nil && b.EdgeHeaderRewrite != nil) || (a.EdgeHeaderRewrite != nil && b.EdgeHeaderRewrite == nil) { + t.Error("Mismatched 'EdgeHeaderRewrite' property; one was nil but the other was not.") + } else if a.EdgeHeaderRewrite != nil && *a.EdgeHeaderRewrite != *b.EdgeHeaderRewrite { + t.Errorf("Mismatched 'EdgeHeaderRewrite' property; one was '%v', the other was '%v'", *a.EdgeHeaderRewrite, *b.EdgeHeaderRewrite) + } + if len(a.ExampleURLs) != len(b.ExampleURLs) { + t.Errorf("Mismatched 'ExampleURLs' property; one contained %d but the other contained %d", len(a.ExampleURLs), len(b.ExampleURLs)) + } else { + for i, eu := range a.ExampleURLs { + if eu != b.ExampleURLs[i] { + t.Errorf("Mismatched 'ExampleURLs[%d]' property; one was '%v', the other was '%v'", i, eu, b.ExampleURLs[i]) + } + } + } + if (a.FirstHeaderRewrite == nil && b.FirstHeaderRewrite != nil) || (a.FirstHeaderRewrite != nil && b.FirstHeaderRewrite == nil) { + t.Error("Mismatched 'FirstHeaderRewrite' property; one was nil but the other was not.") + } else if a.FirstHeaderRewrite != nil && *a.FirstHeaderRewrite != *b.FirstHeaderRewrite { + t.Errorf("Mismatched 'FirstHeaderRewrite' property; one was '%v', the other was '%v'", *a.FirstHeaderRewrite, *b.FirstHeaderRewrite) + } + if (a.FQPacingRate == nil && b.FQPacingRate != nil) || (a.FQPacingRate != nil && b.FQPacingRate == nil) { + t.Error("Mismatched 'FQPacingRate' property; one was nil but the other was not.") + } else if a.FQPacingRate != nil && *a.FQPacingRate != *b.FQPacingRate { + t.Errorf("Mismatched 'FQPacingRate' property; one was '%v', the other was '%v'", *a.FQPacingRate, *b.FQPacingRate) + } + if (a.GeoLimit == nil && b.GeoLimit != nil) || (a.GeoLimit != nil && b.GeoLimit == nil) { + t.Error("Mismatched 'GeoLimit' property; one was nil but the other was not.") + } else if a.GeoLimit != nil && *a.GeoLimit != *b.GeoLimit { + t.Errorf("Mismatched 'GeoLimit' property; one was '%v', the other was '%v'", *a.GeoLimit, *b.GeoLimit) + } + if (a.GeoLimitCountries == nil && b.GeoLimitCountries != nil) || (a.GeoLimitCountries != nil && b.GeoLimitCountries == nil) { + t.Error("Mismatched 'GeoLimitCountries' property; one was nil but the other was not.") + } else if a.GeoLimitCountries != nil && *a.GeoLimitCountries != *b.GeoLimitCountries { + t.Errorf("Mismatched 'GeoLimitCountries' property; one was '%v', the other was '%v'", *a.GeoLimitCountries, *b.GeoLimitCountries) + } + if (a.GeoLimitRedirectURL == nil && b.GeoLimitRedirectURL != nil) || (a.GeoLimitRedirectURL != nil && b.GeoLimitRedirectURL == nil) { + t.Error("Mismatched 'GeoLimitRedirectURL' property; one was nil but the other was not.") + } else if a.GeoLimitRedirectURL != nil && *a.GeoLimitRedirectURL != *b.GeoLimitRedirectURL { + t.Errorf("Mismatched 'GeoLimitRedirectURL' property; one was '%v', the other was '%v'", *a.GeoLimitRedirectURL, *b.GeoLimitRedirectURL) + } + if (a.GeoProvider == nil && b.GeoProvider != nil) || (a.GeoProvider != nil && b.GeoProvider == nil) { + t.Error("Mismatched 'GeoProvider' property; one was nil but the other was not.") + } else if a.GeoProvider != nil && *a.GeoProvider != *b.GeoProvider { + t.Errorf("Mismatched 'GeoProvider' property; one was '%v', the other was '%v'", *a.GeoProvider, *b.GeoProvider) + } + if (a.GlobalMaxMBPS == nil && b.GlobalMaxMBPS != nil) || (a.GlobalMaxMBPS != nil && b.GlobalMaxMBPS == nil) { + t.Error("Mismatched 'GlobalMaxMBPS' property; one was nil but the other was not.") + } else if a.GlobalMaxMBPS != nil && *a.GlobalMaxMBPS != *b.GlobalMaxMBPS { + t.Errorf("Mismatched 'GlobalMaxMBPS' property; one was '%v', the other was '%v'", *a.GlobalMaxMBPS, *b.GlobalMaxMBPS) + } + if (a.GlobalMaxTPS == nil && b.GlobalMaxTPS != nil) || (a.GlobalMaxTPS != nil && b.GlobalMaxTPS == nil) { + t.Error("Mismatched 'GlobalMaxTPS' property; one was nil but the other was not.") + } else if a.GlobalMaxTPS != nil && *a.GlobalMaxTPS != *b.GlobalMaxTPS { + t.Errorf("Mismatched 'GlobalMaxTPS' property; one was '%v', the other was '%v'", *a.GlobalMaxTPS, *b.GlobalMaxTPS) + } + if (a.HTTPBypassFQDN == nil && b.HTTPBypassFQDN != nil) || (a.HTTPBypassFQDN != nil && b.HTTPBypassFQDN == nil) { + t.Error("Mismatched 'HTTPBypassFQDN' property; one was nil but the other was not.") + } else if a.HTTPBypassFQDN != nil && *a.HTTPBypassFQDN != *b.HTTPBypassFQDN { + t.Errorf("Mismatched 'HTTPBypassFQDN' property; one was '%v', the other was '%v'", *a.HTTPBypassFQDN, *b.HTTPBypassFQDN) + } + if (a.ID == nil && b.ID != nil) || (a.ID != nil && b.ID == nil) { + t.Error("Mismatched 'ID' property; one was nil but the other was not.") + } else if a.ID != nil && *a.ID != *b.ID { + t.Errorf("Mismatched 'ID' property; one was '%v', the other was '%v'", *a.ID, *b.ID) + } + if (a.InfoURL == nil && b.InfoURL != nil) || (a.InfoURL != nil && b.InfoURL == nil) { + t.Error("Mismatched 'InfoURL' property; one was nil but the other was not.") + } else if a.InfoURL != nil && *a.InfoURL != *b.InfoURL { + t.Errorf("Mismatched 'InfoURL' property; one was '%v', the other was '%v'", *a.InfoURL, *b.InfoURL) + } + if (a.InitialDispersion == nil && b.InitialDispersion != nil) || (a.InitialDispersion != nil && b.InitialDispersion == nil) { + t.Error("Mismatched 'InitialDispersion' property; one was nil but the other was not.") + } else if a.InitialDispersion != nil && *a.InitialDispersion != *b.InitialDispersion { + t.Errorf("Mismatched 'InitialDispersion' property; one was '%v', the other was '%v'", *a.InitialDispersion, *b.InitialDispersion) + } + if (a.InnerHeaderRewrite == nil && b.InnerHeaderRewrite != nil) || (a.InnerHeaderRewrite != nil && b.InnerHeaderRewrite == nil) { + t.Error("Mismatched 'InnerHeaderRewrite' property; one was nil but the other was not.") + } else if a.InnerHeaderRewrite != nil && *a.InnerHeaderRewrite != *b.InnerHeaderRewrite { + t.Errorf("Mismatched 'InnerHeaderRewrite' property; one was '%v', the other was '%v'", *a.InnerHeaderRewrite, *b.InnerHeaderRewrite) + } + if (a.IPV6RoutingEnabled == nil && b.IPV6RoutingEnabled != nil) || (a.IPV6RoutingEnabled != nil && b.IPV6RoutingEnabled == nil) { + t.Error("Mismatched 'IPV6RoutingEnabled' property; one was nil but the other was not.") + } else if a.IPV6RoutingEnabled != nil && *a.IPV6RoutingEnabled != *b.IPV6RoutingEnabled { + t.Errorf("Mismatched 'IPV6RoutingEnabled' property; one was '%v', the other was '%v'", *a.IPV6RoutingEnabled, *b.IPV6RoutingEnabled) + } + if (a.LastHeaderRewrite == nil && b.LastHeaderRewrite != nil) || (a.LastHeaderRewrite != nil && b.LastHeaderRewrite == nil) { + t.Error("Mismatched 'LastHeaderRewrite' property; one was nil but the other was not.") + } else if a.LastHeaderRewrite != nil && *a.LastHeaderRewrite != *b.LastHeaderRewrite { + t.Errorf("Mismatched 'LastHeaderRewrite' property; one was '%v', the other was '%v'", *a.LastHeaderRewrite, *b.LastHeaderRewrite) + } + if (a.LastUpdated == nil && b.LastUpdated != nil) || (a.LastUpdated != nil && b.LastUpdated == nil) { + t.Error("Mismatched 'LastUpdated' property; one was nil but the other was not.") + } else if a.LastUpdated != nil && *a.LastUpdated != *b.LastUpdated { + t.Errorf("Mismatched 'LastUpdated' property; one was '%v', the other was '%v'", *a.LastUpdated, *b.LastUpdated) + } + if (a.LogsEnabled == nil && b.LogsEnabled != nil) || (a.LogsEnabled != nil && b.LogsEnabled == nil) { + t.Error("Mismatched 'LogsEnabled' property; one was nil but the other was not.") + } else if a.LogsEnabled != nil && *a.LogsEnabled != *b.LogsEnabled { + t.Errorf("Mismatched 'LogsEnabled' property; one was '%v', the other was '%v'", *a.LogsEnabled, *b.LogsEnabled) + } + if (a.LongDesc1 == nil && b.LongDesc1 != nil) || (a.LongDesc1 != nil && b.LongDesc1 == nil) { + t.Error("Mismatched 'LongDesc1' property; one was nil but the other was not.") + } else if a.LongDesc1 != nil && *a.LongDesc1 != *b.LongDesc1 { + t.Errorf("Mismatched 'LongDesc1' property; one was '%v', the other was '%v'", *a.LongDesc1, *b.LongDesc1) + } + if (a.LongDesc2 == nil && b.LongDesc2 != nil) || (a.LongDesc2 != nil && b.LongDesc2 == nil) { + t.Error("Mismatched 'LongDesc2' property; one was nil but the other was not.") + } else if a.LongDesc2 != nil && *a.LongDesc2 != *b.LongDesc2 { + t.Errorf("Mismatched 'LongDesc2' property; one was '%v', the other was '%v'", *a.LongDesc2, *b.LongDesc2) + } + if (a.LongDesc == nil && b.LongDesc != nil) || (a.LongDesc != nil && b.LongDesc == nil) { + t.Error("Mismatched 'LongDesc' property; one was nil but the other was not.") + } else if a.LongDesc != nil && *a.LongDesc != *b.LongDesc { + t.Errorf("Mismatched 'LongDesc' property; one was '%v', the other was '%v'", *a.LongDesc, *b.LongDesc) + } + if (a.MatchList != nil && b.MatchList == nil) || (a.MatchList == nil && b.MatchList != nil) { + t.Error("Mismatched 'MatchList' property; one was nil but the other was not") + } else if a.MatchList != nil { + if len(*a.MatchList) != len(*b.MatchList) { + t.Errorf("Mismatched 'MatchList' property; one contained %d but the other contained %d", len(*a.MatchList), len(*b.MatchList)) + } else { + for i, m := range *a.MatchList { + if m != (*b.MatchList)[i] { + t.Errorf("Mismatched 'MatchList[%d]' property; one was '%v', the other was '%v'", i, m, (*b.MatchList)[i]) + } + } + } + } + if (a.MaxDNSAnswers == nil && b.MaxDNSAnswers != nil) || (a.MaxDNSAnswers != nil && b.MaxDNSAnswers == nil) { + t.Error("Mismatched 'MaxDNSAnswers' property; one was nil but the other was not.") + } else if a.MaxDNSAnswers != nil && *a.MaxDNSAnswers != *b.MaxDNSAnswers { + t.Errorf("Mismatched 'MaxDNSAnswers' property; one was '%v', the other was '%v'", *a.MaxDNSAnswers, *b.MaxDNSAnswers) + } + if (a.MaxOriginConnections == nil && b.MaxOriginConnections != nil) || (a.MaxOriginConnections != nil && b.MaxOriginConnections == nil) { + t.Error("Mismatched 'MaxOriginConnections' property; one was nil but the other was not.") + } else if a.MaxOriginConnections != nil && *a.MaxOriginConnections != *b.MaxOriginConnections { + t.Errorf("Mismatched 'MaxOriginConnections' property; one was '%v', the other was '%v'", *a.MaxOriginConnections, *b.MaxOriginConnections) + } + if (a.MaxRequestHeaderBytes == nil && b.MaxRequestHeaderBytes != nil) || (a.MaxRequestHeaderBytes != nil && b.MaxRequestHeaderBytes == nil) { + t.Error("Mismatched 'MaxRequestHeaderBytes' property; one was nil but the other was not.") + } else if a.MaxRequestHeaderBytes != nil && *a.MaxRequestHeaderBytes != *b.MaxRequestHeaderBytes { + t.Errorf("Mismatched 'MaxRequestHeaderBytes' property; one was '%v', the other was '%v'", *a.MaxRequestHeaderBytes, *b.MaxRequestHeaderBytes) + } + if (a.MidHeaderRewrite == nil && b.MidHeaderRewrite != nil) || (a.MidHeaderRewrite != nil && b.MidHeaderRewrite == nil) { + t.Error("Mismatched 'MidHeaderRewrite' property; one was nil but the other was not.") + } else if a.MidHeaderRewrite != nil && *a.MidHeaderRewrite != *b.MidHeaderRewrite { + t.Errorf("Mismatched 'MidHeaderRewrite' property; one was '%v', the other was '%v'", *a.MidHeaderRewrite, *b.MidHeaderRewrite) + } + if (a.MissLat == nil && b.MissLat != nil) || (a.MissLat != nil && b.MissLat == nil) { + t.Error("Mismatched 'MissLat' property; one was nil but the other was not.") + } else if a.MissLat != nil && *a.MissLat != *b.MissLat { + t.Errorf("Mismatched 'MissLat' property; one was '%v', the other was '%v'", *a.MissLat, *b.MissLat) + } + if (a.MissLong == nil && b.MissLong != nil) || (a.MissLong != nil && b.MissLong == nil) { + t.Error("Mismatched 'MissLong' property; one was nil but the other was not.") + } else if a.MissLong != nil && *a.MissLong != *b.MissLong { + t.Errorf("Mismatched 'MissLong' property; one was '%v', the other was '%v'", *a.MissLong, *b.MissLong) + } + if (a.MultiSiteOrigin == nil && b.MultiSiteOrigin != nil) || (a.MultiSiteOrigin != nil && b.MultiSiteOrigin == nil) { + t.Error("Mismatched 'MultiSiteOrigin' property; one was nil but the other was not.") + } else if a.MultiSiteOrigin != nil && *a.MultiSiteOrigin != *b.MultiSiteOrigin { + t.Errorf("Mismatched 'MultiSiteOrigin' property; one was '%v', the other was '%v'", *a.MultiSiteOrigin, *b.MultiSiteOrigin) + } + if (a.OrgServerFQDN == nil && b.OrgServerFQDN != nil) || (a.OrgServerFQDN != nil && b.OrgServerFQDN == nil) { + t.Error("Mismatched 'OrgServerFQDN' property; one was nil but the other was not.") + } else if a.OrgServerFQDN != nil && *a.OrgServerFQDN != *b.OrgServerFQDN { + t.Errorf("Mismatched 'OrgServerFQDN' property; one was '%v', the other was '%v'", *a.OrgServerFQDN, *b.OrgServerFQDN) + } + if (a.OriginShield == nil && b.OriginShield != nil) || (a.OriginShield != nil && b.OriginShield == nil) { + t.Error("Mismatched 'OriginShield' property; one was nil but the other was not.") + } else if a.OriginShield != nil && *a.OriginShield != *b.OriginShield { + t.Errorf("Mismatched 'OriginShield' property; one was '%v', the other was '%v'", *a.OriginShield, *b.OriginShield) + } + if (a.ProfileDesc == nil && b.ProfileDesc != nil) || (a.ProfileDesc != nil && b.ProfileDesc == nil) { + t.Error("Mismatched 'ProfileDesc' property; one was nil but the other was not.") + } else if a.ProfileDesc != nil && *a.ProfileDesc != *b.ProfileDesc { + t.Errorf("Mismatched 'ProfileDesc' property; one was '%v', the other was '%v'", *a.ProfileDesc, *b.ProfileDesc) + } + if (a.ProfileID == nil && b.ProfileID != nil) || (a.ProfileID != nil && b.ProfileID == nil) { + t.Error("Mismatched 'ProfileID' property; one was nil but the other was not.") + } else if a.ProfileID != nil && *a.ProfileID != *b.ProfileID { + t.Errorf("Mismatched 'ProfileID' property; one was '%v', the other was '%v'", *a.ProfileID, *b.ProfileID) + } + if (a.ProfileName == nil && b.ProfileName != nil) || (a.ProfileName != nil && b.ProfileName == nil) { + t.Error("Mismatched 'ProfileName' property; one was nil but the other was not.") + } else if a.ProfileName != nil && *a.ProfileName != *b.ProfileName { + t.Errorf("Mismatched 'ProfileName' property; one was '%v', the other was '%v'", *a.ProfileName, *b.ProfileName) + } + if (a.Protocol == nil && b.Protocol != nil) || (a.Protocol != nil && b.Protocol == nil) { + t.Error("Mismatched 'Protocol' property; one was nil but the other was not.") + } else if a.Protocol != nil && *a.Protocol != *b.Protocol { + t.Errorf("Mismatched 'Protocol' property; one was '%v', the other was '%v'", *a.Protocol, *b.Protocol) + } + if (a.QStringIgnore == nil && b.QStringIgnore != nil) || (a.QStringIgnore != nil && b.QStringIgnore == nil) { + t.Error("Mismatched 'QStringIgnore' property; one was nil but the other was not.") + } else if a.QStringIgnore != nil && *a.QStringIgnore != *b.QStringIgnore { + t.Errorf("Mismatched 'QStringIgnore' property; one was '%v', the other was '%v'", *a.QStringIgnore, *b.QStringIgnore) + } + if (a.RangeRequestHandling == nil && b.RangeRequestHandling != nil) || (a.RangeRequestHandling != nil && b.RangeRequestHandling == nil) { + t.Error("Mismatched 'RangeRequestHandling' property; one was nil but the other was not.") + } else if a.RangeRequestHandling != nil && *a.RangeRequestHandling != *b.RangeRequestHandling { + t.Errorf("Mismatched 'RangeRequestHandling' property; one was '%v', the other was '%v'", *a.RangeRequestHandling, *b.RangeRequestHandling) + } + if (a.RangeSliceBlockSize == nil && b.RangeSliceBlockSize != nil) || (a.RangeSliceBlockSize != nil && b.RangeSliceBlockSize == nil) { + t.Error("Mismatched 'RangeSliceBlockSize' property; one was nil but the other was not.") + } else if a.RangeSliceBlockSize != nil && *a.RangeSliceBlockSize != *b.RangeSliceBlockSize { + t.Errorf("Mismatched 'RangeSliceBlockSize' property; one was '%v', the other was '%v'", *a.RangeSliceBlockSize, *b.RangeSliceBlockSize) + } + if (a.RegexRemap == nil && b.RegexRemap != nil) || (a.RegexRemap != nil && b.RegexRemap == nil) { + t.Error("Mismatched 'RegexRemap' property; one was nil but the other was not.") + } else if a.RegexRemap != nil && *a.RegexRemap != *b.RegexRemap { + t.Errorf("Mismatched 'RegexRemap' property; one was '%v', the other was '%v'", *a.RegexRemap, *b.RegexRemap) + } + if (a.RegionalGeoBlocking == nil && b.RegionalGeoBlocking != nil) || (a.RegionalGeoBlocking != nil && b.RegionalGeoBlocking == nil) { + t.Error("Mismatched 'RegionalGeoBlocking' property; one was nil but the other was not.") + } else if a.RegionalGeoBlocking != nil && *a.RegionalGeoBlocking != *b.RegionalGeoBlocking { + t.Errorf("Mismatched 'RegionalGeoBlocking' property; one was '%v', the other was '%v'", *a.RegionalGeoBlocking, *b.RegionalGeoBlocking) + } + if (a.RemapText == nil && b.RemapText != nil) || (a.RemapText != nil && b.RemapText == nil) { + t.Error("Mismatched 'RemapText' property; one was nil but the other was not.") + } else if a.RemapText != nil && *a.RemapText != *b.RemapText { + t.Errorf("Mismatched 'RemapText' property; one was '%v', the other was '%v'", *a.RemapText, *b.RemapText) + } + if (a.RoutingName == nil && b.RoutingName != nil) || (a.RoutingName != nil && b.RoutingName == nil) { + t.Error("Mismatched 'RoutingName' property; one was nil but the other was not.") + } else if a.RoutingName != nil && *a.RoutingName != *b.RoutingName { + t.Errorf("Mismatched 'RoutingName' property; one was '%v', the other was '%v'", *a.RoutingName, *b.RoutingName) + } + if (a.ServiceCategory == nil && b.ServiceCategory != nil) || (a.ServiceCategory != nil && b.ServiceCategory == nil) { + t.Error("Mismatched 'ServiceCategory' property; one was nil but the other was not.") + } else if a.ServiceCategory != nil && *a.ServiceCategory != *b.ServiceCategory { + t.Errorf("Mismatched 'ServiceCategory' property; one was '%v', the other was '%v'", *a.ServiceCategory, *b.ServiceCategory) + } + if a.Signed != b.Signed { + t.Errorf("Mismatched 'Signed' property; one was '%v', the other was '%v'", a.Signed, b.Signed) + } + if (a.SigningAlgorithm == nil && b.SigningAlgorithm != nil) || (a.SigningAlgorithm != nil && b.SigningAlgorithm == nil) { + t.Error("Mismatched 'SigningAlgorithm' property; one was nil but the other was not.") + } else if a.SigningAlgorithm != nil && *a.SigningAlgorithm != *b.SigningAlgorithm { + t.Errorf("Mismatched 'SigningAlgorithm' property; one was '%v', the other was '%v'", *a.SigningAlgorithm, *b.SigningAlgorithm) + } + if (a.SSLKeyVersion == nil && b.SSLKeyVersion != nil) || (a.SSLKeyVersion != nil && b.SSLKeyVersion == nil) { + t.Error("Mismatched 'SSLKeyVersion' property; one was nil but the other was not.") + } else if a.SSLKeyVersion != nil && *a.SSLKeyVersion != *b.SSLKeyVersion { + t.Errorf("Mismatched 'SSLKeyVersion' property; one was '%v', the other was '%v'", *a.SSLKeyVersion, *b.SSLKeyVersion) + } + if (a.Tenant == nil && b.Tenant != nil) || (a.Tenant != nil && b.Tenant == nil) { + t.Error("Mismatched 'Tenant' property; one was nil but the other was not.") + } else if a.Tenant != nil && *a.Tenant != *b.Tenant { + t.Errorf("Mismatched 'Tenant' property; one was '%v', the other was '%v'", *a.Tenant, *b.Tenant) + } + if (a.TenantID == nil && b.TenantID != nil) || (a.TenantID != nil && b.TenantID == nil) { + t.Error("Mismatched 'TenantID' property; one was nil but the other was not.") + } else if a.TenantID != nil && *a.TenantID != *b.TenantID { + t.Errorf("Mismatched 'TenantID' property; one was '%v', the other was '%v'", *a.TenantID, *b.TenantID) + } + if (a.Topology == nil && b.Topology != nil) || (a.Topology != nil && b.Topology == nil) { + t.Error("Mismatched 'Topology' property; one was nil but the other was not.") + } else if a.Topology != nil && *a.Topology != *b.Topology { + t.Errorf("Mismatched 'Topology' property; one was '%v', the other was '%v'", *a.Topology, *b.Topology) + } + if (a.TRRequestHeaders == nil && b.TRRequestHeaders != nil) || (a.TRRequestHeaders != nil && b.TRRequestHeaders == nil) { + t.Error("Mismatched 'TRRequestHeaders' property; one was nil but the other was not.") + } else if a.TRRequestHeaders != nil && *a.TRRequestHeaders != *b.TRRequestHeaders { + t.Errorf("Mismatched 'TRRequestHeaders' property; one was '%v', the other was '%v'", *a.TRRequestHeaders, *b.TRRequestHeaders) + } + if (a.TRResponseHeaders == nil && b.TRResponseHeaders != nil) || (a.TRResponseHeaders != nil && b.TRResponseHeaders == nil) { + t.Error("Mismatched 'TRResponseHeaders' property; one was nil but the other was not.") + } else if a.TRResponseHeaders != nil && *a.TRResponseHeaders != *b.TRResponseHeaders { + t.Errorf("Mismatched 'TRResponseHeaders' property; one was '%v', the other was '%v'", *a.TRResponseHeaders, *b.TRResponseHeaders) + } + if (a.Type == nil && b.Type != nil) || (a.Type != nil && b.Type == nil) { + t.Error("Mismatched 'Type' property; one was nil but the other was not.") + } else if a.Type != nil && *a.Type != *b.Type { + t.Errorf("Mismatched 'Type' property; one was '%v', the other was '%v'", *a.Type, *b.Type) + } + if (a.TypeID == nil && b.TypeID != nil) || (a.TypeID != nil && b.TypeID == nil) { + t.Error("Mismatched 'TypeID' property; one was nil but the other was not.") + } else if a.TypeID != nil && *a.TypeID != *b.TypeID { + t.Errorf("Mismatched 'TypeID' property; one was '%v', the other was '%v'", *a.TypeID, *b.TypeID) + } + if (a.XMLID == nil && b.XMLID != nil) || (a.XMLID != nil && b.XMLID == nil) { + t.Error("Mismatched 'XMLID' property; one was nil but the other was not.") + } else if a.XMLID != nil && *a.XMLID != *b.XMLID { + t.Errorf("Mismatched 'XMLID' property; one was '%v', the other was '%v'", *a.XMLID, *b.XMLID) + } +} + +// This gets equivalent legacy and new Delivery Services, for testing comparisons. +func dsUpgradeAndDowngradeTestingPair() (DeliveryServiceNullableV30, DeliveryServiceV4) { + anonymousBlockingEnabled := false + cacheURL := "testquest" + cCRDNSTTL := 42 + cdnID := -12 + cdnName := "cdnName" + checkPath := "checkPath" + consistentHashQueryParams := []string{"consistent", "hash", "query", "params"} + consistentHashRegex := "consistentHashRegex" + deepCachingType := DeepCachingTypeNever + displayName := "displayName" + dnsBypassCNAME := "dnsBypassCNAME" + dnsBypassIP := "dnsBypassIP" + dnsBypassIP6 := "dnsBypassIP6" + dnsBypassTTL := 100 + dscp := -69 + ecsEnabled := true + edgeHeaderRewrite := "edgeHeaderRewrite" + exampleURLs := []string{"http://example", "https://URLs"} + firstHeaderRewrite := "firstHeaderRewrite" + fqPacingRate := 1337 + geoLimit := 2 + geoLimitCountries := "geo,Limit,Countries" + geoLimitRedirectURL := "wss://geoLimitRedirectURL" + geoProvider := 1 + globalMaxMBPS := -72485 + globalMaxTPS := 867 + hTTPBypassFQDN := "hTTPBypassFQDN" + id := -1551 + infoURL := "infoURL" + initialDispersion := 65154 + innerHeaderRewrite := "innerHeaderRewrite" + ipv6RoutingEnabled := false + lastHeaderRewrite := "lastHeaderRewrite" + lastUpdated := NewTimeNoMod() + logsEnabled := true + longDesc := "longDesc" + longDesc1 := "longDesc1" + longDesc2 := "longDesc2" + maxDNSAnswers := -76675 + maxOriginConnections := 6514684 + maxRequestHeaderBytes := 555 + midHeaderRewrite := "midHeaderRewrite" + missLat := -98.171455 + missLong := 42.122167 + multiSiteOrigin := false + originShield := "originShield" + orgServerFQDN := "orgServerFQDN" + profileDesc := "profileDesc" + profileID := -4657 + profileName := "profileName" + protocol := 87487 + qstringIgnore := -474 + rangeRequestHandling := 16716 + rangeSliceBlockSize := -92559 + regexRemap := "regexRemap" + regionalGeoBlocking := true + remapText := "remapText" + routingName := "routingName" + serviceCategory := "serviceCategory" + signed := false + signingAlgorithm := "signingAlgorithm" + sSLKeyVersion := 721574 + tenant := "tenant" + tenantID := -6551 + topology := "topology" + trResponseHeaders := "trResponseHeaders" + trRequestHeaders := "trRequestHeaders" + typ := DSTypeDNS + typeID := 22 + xmlid := "xmlid" + + newDS := DeliveryServiceV4{ + Active: false, + AnonymousBlockingEnabled: anonymousBlockingEnabled, + CCRDNSTTL: &cCRDNSTTL, + CDNID: cdnID, + CDNName: &cdnName, + CheckPath: &checkPath, + ConsistentHashQueryParams: consistentHashQueryParams, + ConsistentHashRegex: &consistentHashRegex, + DeepCachingType: deepCachingType, + DisplayName: displayName, + DNSBypassCNAME: &dnsBypassCNAME, + DNSBypassIP: &dnsBypassIP, + DNSBypassIP6: &dnsBypassIP6, + DNSBypassTTL: &dnsBypassTTL, + DSCP: dscp, + EcsEnabled: ecsEnabled, + EdgeHeaderRewrite: &edgeHeaderRewrite, + ExampleURLs: exampleURLs, + FirstHeaderRewrite: &firstHeaderRewrite, + FQPacingRate: &fqPacingRate, + GeoLimit: geoLimit, + GeoLimitCountries: &geoLimitCountries, + GeoLimitRedirectURL: &geoLimitRedirectURL, + GeoProvider: geoProvider, + GlobalMaxMBPS: &globalMaxMBPS, + GlobalMaxTPS: &globalMaxTPS, + HTTPBypassFQDN: &hTTPBypassFQDN, + ID: &id, + InfoURL: &infoURL, + InitialDispersion: &initialDispersion, + InnerHeaderRewrite: &innerHeaderRewrite, + IPV6RoutingEnabled: ipv6RoutingEnabled, + LastHeaderRewrite: &lastHeaderRewrite, + LastUpdated: lastUpdated.Time, + LogsEnabled: logsEnabled, + LongDesc: &longDesc, + LongDesc1: &longDesc1, + LongDesc2: &longDesc2, + MatchList: nil, + MaxDNSAnswers: &maxDNSAnswers, + MaxOriginConnections: &maxOriginConnections, + MaxRequestHeaderBytes: &maxRequestHeaderBytes, + MidHeaderRewrite: &midHeaderRewrite, + MissLat: &missLat, + MissLong: &missLong, + MultiSiteOrigin: &multiSiteOrigin, + OriginShield: &originShield, + OrgServerFQDN: &orgServerFQDN, + ProfileDesc: &profileDesc, + ProfileID: &profileID, + ProfileName: &profileName, + Protocol: &protocol, + QStringIgnore: &qstringIgnore, + RangeRequestHandling: &rangeRequestHandling, + RangeSliceBlockSize: &rangeSliceBlockSize, + RegexRemap: ®exRemap, + RegionalGeoBlocking: regionalGeoBlocking, + RemapText: &remapText, + RoutingName: routingName, + ServiceCategory: &serviceCategory, + Signed: signed, + SigningAlgorithm: &signingAlgorithm, + SSLKeyVersion: &sSLKeyVersion, + Tenant: &tenant, + TenantID: tenantID, + TLSVersions: []string{"1.0", "1.1", "1.2", "1.3"}, + Topology: &topology, + TRResponseHeaders: &trResponseHeaders, + TRRequestHeaders: &trRequestHeaders, + Type: &typ, + TypeID: typeID, + XMLID: xmlid, + } + + active := false + oldDS := DeliveryServiceNullableV30{ + DeliveryServiceV30: DeliveryServiceV30{ + DeliveryServiceNullableV15: DeliveryServiceNullableV15{ + DeliveryServiceNullableV14: DeliveryServiceNullableV14{ + DeliveryServiceNullableV13: DeliveryServiceNullableV13{ + DeliveryServiceNullableV12: DeliveryServiceNullableV12{ + DeliveryServiceNullableV11: DeliveryServiceNullableV11{ + DeliveryServiceNullableFieldsV11: DeliveryServiceNullableFieldsV11{ + Active: &active, + AnonymousBlockingEnabled: &anonymousBlockingEnabled, + CCRDNSTTL: &cCRDNSTTL, + CDNID: &cdnID, + CDNName: &cdnName, + CheckPath: &checkPath, + DisplayName: &displayName, + DNSBypassCNAME: &dnsBypassCNAME, + DNSBypassIP: &dnsBypassIP, + DNSBypassIP6: &dnsBypassIP6, + DNSBypassTTL: &dnsBypassTTL, + DSCP: &dscp, + EdgeHeaderRewrite: &edgeHeaderRewrite, + ExampleURLs: exampleURLs, + GeoLimit: &geoLimit, + GeoLimitCountries: &geoLimitCountries, + GeoLimitRedirectURL: &geoLimitRedirectURL, + GeoProvider: &geoProvider, + GlobalMaxMBPS: &globalMaxMBPS, + GlobalMaxTPS: &globalMaxTPS, + HTTPBypassFQDN: &hTTPBypassFQDN, + ID: &id, + InfoURL: &infoURL, + InitialDispersion: &initialDispersion, + IPV6RoutingEnabled: &ipv6RoutingEnabled, + LastUpdated: lastUpdated, + LogsEnabled: &logsEnabled, + LongDesc: &longDesc, + LongDesc1: &longDesc1, + LongDesc2: &longDesc2, + MatchList: nil, + MaxDNSAnswers: &maxDNSAnswers, + MidHeaderRewrite: &midHeaderRewrite, + MissLat: &missLat, + MissLong: &missLong, + MultiSiteOrigin: &multiSiteOrigin, + OriginShield: &originShield, + OrgServerFQDN: &orgServerFQDN, + ProfileDesc: &profileDesc, + ProfileID: &profileID, + ProfileName: &profileName, + Protocol: &protocol, + QStringIgnore: &qstringIgnore, + RangeRequestHandling: &rangeRequestHandling, + RegexRemap: ®exRemap, + RegionalGeoBlocking: ®ionalGeoBlocking, + RemapText: &remapText, + RoutingName: &routingName, + Signed: signed, + SSLKeyVersion: &sSLKeyVersion, + TenantID: &tenantID, + Type: &typ, + TypeID: &typeID, + XMLID: &xmlid, + }, + DeliveryServiceRemovedFieldsV11: DeliveryServiceRemovedFieldsV11{ + CacheURL: &cacheURL, + }, + }, + }, + DeliveryServiceFieldsV13: DeliveryServiceFieldsV13{ + DeepCachingType: &deepCachingType, + FQPacingRate: &fqPacingRate, + SigningAlgorithm: &signingAlgorithm, + Tenant: &tenant, + TRResponseHeaders: &trResponseHeaders, + TRRequestHeaders: &trRequestHeaders, + }, + }, + DeliveryServiceFieldsV14: DeliveryServiceFieldsV14{ + ConsistentHashQueryParams: consistentHashQueryParams, + ConsistentHashRegex: &consistentHashRegex, + MaxOriginConnections: &maxOriginConnections, + }, + }, + DeliveryServiceFieldsV15: DeliveryServiceFieldsV15{ + EcsEnabled: ecsEnabled, + RangeSliceBlockSize: &rangeSliceBlockSize, + }, + }, + DeliveryServiceFieldsV30: DeliveryServiceFieldsV30{ + FirstHeaderRewrite: &firstHeaderRewrite, + InnerHeaderRewrite: &innerHeaderRewrite, + LastHeaderRewrite: &lastHeaderRewrite, + ServiceCategory: &serviceCategory, + Topology: &topology, + }, + }, + DeliveryServiceFieldsV31: DeliveryServiceFieldsV31{ + MaxRequestHeaderBytes: &maxRequestHeaderBytes, + }, + } + + return oldDS, newDS +} + +func TestDeliveryServiceUpgradeAndDowngrade(t *testing.T) { + oldDS, newDS := dsUpgradeAndDowngradeTestingPair() + compareV31DSes(oldDS, newDS.DowngradeToV3(), t) + + nullableOldDS := DeliveryServiceNullableV30(oldDS) + upgraded := nullableOldDS.UpgradeToV4() + compareV31DSes(upgraded.DowngradeToV3(), newDS.DowngradeToV3(), t) + + downgraded := newDS.DowngradeToV3() + upgraded = downgraded.UpgradeToV4() + downgraded = upgraded.DowngradeToV3() + compareV31DSes(oldDS, downgraded, t) + + upgraded = nullableOldDS.UpgradeToV4() + downgraded = newDS.DowngradeToV3() + tmp := downgraded.UpgradeToV4() + downgraded = tmp.DowngradeToV3() + compareV31DSes(upgraded.DowngradeToV3(), downgraded, t) + + if oldDS.CacheURL == nil { + oldDS.CacheURL = new(string) + *oldDS.CacheURL = "testquest" + } + + upgraded = oldDS.UpgradeToV4() + downgraded = upgraded.DowngradeToV3() + if downgraded.CacheURL != nil { + t.Error("Expected 'cacheurl' to be null after upgrade then downgrade because it doesn't exist in APIv4, but it wasn't") + } + + downgraded = newDS.DowngradeToV3() + upgraded = downgraded.UpgradeToV4() + if upgraded.TLSVersions != nil { + t.Errorf("Expected 'tlsVersions' to be nil after upgrade, because all TLS versions are implicitly supported for an APIv3 DS; found: %v", upgraded.TLSVersions) + } +} diff --git a/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go b/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go index 2546d92585..eeb08098ae 100644 --- a/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go +++ b/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go @@ -159,12 +159,8 @@ func setInactive(t *testing.T, dsID int) { } ds := resp.Response[0] - if ds.Active == nil { - t.Errorf("Deliver Service #%d had null or undefined 'active'", dsID) - ds.Active = new(bool) - } - if *ds.Active { - *ds.Active = false + if ds.Active { + ds.Active = false _, _, err = TOSession.UpdateDeliveryService(dsID, ds, client.RequestOptions{}) if err != nil { t.Errorf("Failed to set Delivery Service #%d to inactive: %v", dsID, err) diff --git a/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go b/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go index edc5103a8e..92061e9957 100644 --- a/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go +++ b/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go @@ -105,22 +105,22 @@ func CreateTestDeliveryServiceRequestComments(t *testing.T) { ds = dsr.Requested } resetDS(ds) - if ds == nil || ds.XMLID == nil { - t.Fatal("first DSR in the test data had a nil DeliveryService or one with no XMLID") + if ds == nil { + t.Fatal("first DSR in the test data had a nil Delivery Service") } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Fatalf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) + t.Fatalf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) } if len(resp.Response) != 1 { - t.Fatalf("found %d Delivery Service request by XMLID '%s, expected exactly one", len(resp.Response), *ds.XMLID) + t.Fatalf("found %d Delivery Service request by XMLID '%s, expected exactly one", len(resp.Response), ds.XMLID) } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("got Delivery Service Request with xml_id '%s' that had a null ID", *ds.XMLID) + t.Fatalf("got Delivery Service Request with xml_id '%s' that had a null ID", ds.XMLID) } for _, comment := range testData.DeliveryServiceRequestComments { diff --git a/traffic_ops/testing/api/v4/deliveryservice_requests_test.go b/traffic_ops/testing/api/v4/deliveryservice_requests_test.go index 1f2652fd76..5b072856e2 100644 --- a/traffic_ops/testing/api/v4/deliveryservice_requests_test.go +++ b/traffic_ops/testing/api/v4/deliveryservice_requests_test.go @@ -49,11 +49,11 @@ func resetDS(ds *tc.DeliveryServiceV4) { if ds == nil { return } - ds.CDNID = nil + ds.CDNID = 0 ds.ID = nil ds.ProfileID = nil - ds.TenantID = nil - ds.TypeID = nil + ds.TenantID = 0 + ds.TypeID = 0 } func TestDeliveryServiceRequests(t *testing.T) { @@ -147,25 +147,25 @@ func UpdateTestDeliveryServiceRequestsWithHeaders(t *testing.T, header http.Head ds = dsr.Requested } resetDS(ds) - if ds == nil || ds.XMLID == nil { - t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrGood) + if ds == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) } opts := client.NewRequestOptions() opts.Header = header - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) + t.Errorf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) } if len(resp.Response) == 0 { t.Fatal("Length of GET DeliveryServiceRequest is 0") } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("Got a DSR for XML ID '%s' that had a nil ID", *ds.XMLID) + t.Fatalf("Got a DSR for XML ID '%s' that had a nil ID", ds.XMLID) } if respDSR.ChangeType != dsr.ChangeType { - t.Fatalf("remote representation of DSR with XMLID '%s' differed from stored data", *ds.XMLID) + t.Fatalf("remote representation of DSR with XMLID '%s' differed from stored data", ds.XMLID) } var respDS *tc.DeliveryServiceV4 if respDSR.ChangeType == tc.DSRChangeTypeDelete { @@ -174,8 +174,7 @@ func UpdateTestDeliveryServiceRequestsWithHeaders(t *testing.T, header http.Head respDS = respDSR.Requested } - respDS.DisplayName = new(string) - *respDS.DisplayName = "new display name" + respDS.DisplayName = "new display name" opts.QueryParameters.Del("xmlId") _, reqInf, err := TOSession.UpdateDeliveryServiceRequest(*respDSR.ID, respDSR, opts) if err == nil { @@ -201,13 +200,13 @@ func GetTestDeliveryServiceRequestsIMSAfterChange(t *testing.T, header http.Head } resetDS(ds) - if ds == nil || ds.XMLID == nil { - t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrGood) + if ds == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) } opts := client.NewRequestOptions() opts.Header = header - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) resp, reqInf, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { t.Fatalf("Expected no error, but got: %v - alerts: %+v", err, resp.Alerts) @@ -284,9 +283,9 @@ func TestDeliveryServiceRequestRules(t *testing.T) { if ds == nil { t.Fatalf("the %dth DSR in the test data had no DeliveryService", dsrGood) } - ds.DisplayName = &displayName - ds.RoutingName = &routingName - ds.XMLID = &XMLID + ds.DisplayName = displayName + ds.RoutingName = routingName + ds.XMLID = XMLID _, _, err := TOSession.CreateDeliveryServiceRequest(dsr, client.RequestOptions{}) if err == nil { @@ -311,8 +310,8 @@ func TestDeliveryServiceRequestTypeFields(t *testing.T) { ds = dsr.Requested } resetDS(ds) - if ds == nil || ds.XMLID == nil { - t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrBadTenant) + if ds == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrBadTenant) } resp, _, err := TOSession.CreateDeliveryServiceRequest(dsr, client.RequestOptions{}) @@ -335,16 +334,16 @@ func TestDeliveryServiceRequestTypeFields(t *testing.T) { } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) dsrs, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("Unexpected error retriving Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, dsrs.Alerts) + t.Errorf("Unexpected error retriving Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, dsrs.Alerts) } if len(dsrs.Response) != 1 { - t.Fatalf("expected exactly one Deliveryservice Request with XMLID '%s'; got %d", *ds.XMLID, len(dsrs.Response)) + t.Fatalf("expected exactly one Deliveryservice Request with XMLID '%s'; got %d", ds.XMLID, len(dsrs.Response)) } if dsrs.Response[0].ID == nil { - t.Fatalf("got a DSR with a null ID by XMLID '%s'", *ds.XMLID) + t.Fatalf("got a DSR with a null ID by XMLID '%s'", ds.XMLID) } alert, _, err := TOSession.DeleteDeliveryServiceRequest(*dsrs.Response[0].ID, client.RequestOptions{}) @@ -521,14 +520,14 @@ func GetTestDeliveryServiceRequestsIMS(t *testing.T) { ds = dsr.Requested } resetDS(ds) - if ds == nil || ds.XMLID == nil { - t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrGood) + if ds == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) } - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) resp, reqInf, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Fatalf("Unexpected error getting Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) + t.Fatalf("Unexpected error getting Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) } if reqInf.StatusCode != http.StatusNotModified { t.Fatalf("Expected 304 status code, got %v", reqInf.StatusCode) @@ -550,15 +549,15 @@ func GetTestDeliveryServiceRequests(t *testing.T) { } resetDS(ds) - if ds == nil || ds.XMLID == nil { - t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrGood) + if ds == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) + t.Errorf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) } } @@ -579,22 +578,22 @@ func UpdateTestDeliveryServiceRequests(t *testing.T) { } resetDS(ds) - if ds == nil || ds.XMLID == nil { - t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrGood) + if ds == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("cannot get Delivery Service Request with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) + t.Errorf("cannot get Delivery Service Request with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Deliver Service Request to exist with XMLID '%s', but none were found in Traffic Ops", *ds.XMLID) + t.Fatalf("Expected at least one Deliver Service Request to exist with XMLID '%s', but none were found in Traffic Ops", ds.XMLID) } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("got a DSR by XMLID '%s' with a null or undefined ID", *ds.XMLID) + t.Fatalf("got a DSR by XMLID '%s' with a null or undefined ID", ds.XMLID) } var respDS *tc.DeliveryServiceV4 if dsr.ChangeType == tc.DSRChangeTypeDelete { @@ -603,7 +602,7 @@ func UpdateTestDeliveryServiceRequests(t *testing.T) { respDS = dsr.Requested } expDisplayName := "new display name" - respDS.DisplayName = &expDisplayName + respDS.DisplayName = expDisplayName id := *respDSR.ID alerts, _, err := TOSession.UpdateDeliveryServiceRequest(id, respDSR, client.RequestOptions{}) if err != nil { @@ -629,11 +628,11 @@ func UpdateTestDeliveryServiceRequests(t *testing.T) { respDS = dsr.Requested } - if respDS == nil || respDS.DisplayName == nil { - t.Fatalf("Got DSR by ID '%d' that had no DeliveryService - or said DeliveryService had no DisplayName", id) + if respDS == nil { + t.Fatalf("Got DSR by ID '%d' that had no Delivery Service", id) } - if *respDS.DisplayName != expDisplayName { - t.Errorf("results do not match actual: %s, expected: %s", *respDS.DisplayName, expDisplayName) + if respDS.DisplayName != expDisplayName { + t.Errorf("results do not match actual: %s, expected: %s", respDS.DisplayName, expDisplayName) } } @@ -654,22 +653,22 @@ func DeleteTestDeliveryServiceRequests(t *testing.T) { } resetDS(ds) - if ds == nil || ds.XMLID == nil { + if ds == nil { t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrGood) } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", *ds.XMLID) + opts.QueryParameters.Set("xmlId", ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Fatalf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) + t.Fatalf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) } if len(resp.Response) < 1 { - t.Fatalf("expected at least one Delivery Service Request to have XMLID '%s', got none", *ds.XMLID) + t.Fatalf("expected at least one Delivery Service Request to have XMLID '%s', got none", ds.XMLID) } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("Got a DSR by XMLID '%s' that had no ID", *ds.XMLID) + t.Fatalf("Got a DSR by XMLID '%s' that had no ID", ds.XMLID) } alert, _, err := TOSession.DeleteDeliveryServiceRequest(*respDSR.ID, client.RequestOptions{}) if err != nil { diff --git a/traffic_ops/testing/api/v4/deliveryservices_test.go b/traffic_ops/testing/api/v4/deliveryservices_test.go index 0630a2efb8..f398b1e06e 100644 --- a/traffic_ops/testing/api/v4/deliveryservices_test.go +++ b/traffic_ops/testing/api/v4/deliveryservices_test.go @@ -194,9 +194,6 @@ func UpdateTestDeliveryServicesWithHeaders(t *testing.T, header http.Header) { t.Fatal("Need at least one Delivery Service to test updating Delivery Services with HTTP Headers") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatalf("couldn't get the xml ID of test DS") - } opts := client.RequestOptions{Header: header} dses, _, err := TOSession.GetDeliveryServices(opts) @@ -207,17 +204,17 @@ func UpdateTestDeliveryServicesWithHeaders(t *testing.T, header http.Header) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.XMLID != nil && *ds.XMLID == *firstDS.XMLID { + if ds.XMLID == firstDS.XMLID { found = true remoteDS = ds break } } if !found { - t.Fatalf("GET Delivery Services missing: %v", *firstDS.XMLID) + t.Fatalf("GET Delivery Services missing: %v", firstDS.XMLID) } if remoteDS.ID == nil { - t.Fatalf("Traffic Ops returned a representation for Delivery Service '%s' that had a null or undefined ID", *firstDS.XMLID) + t.Fatalf("Traffic Ops returned a representation for Delivery Service '%s' that had a null or undefined ID", firstDS.XMLID) } updatedLongDesc := "something different" @@ -272,11 +269,7 @@ func createBlankCDN(cdnName string, t *testing.T) tc.CDN { } func cleanUp(t *testing.T, ds tc.DeliveryServiceV4, oldCDNID int, newCDNID int, sslKeyVersions []string) { - if ds.XMLID == nil { - t.Error("Cannot clean up Delivery Service with nil XMLID") - return - } - xmlid := *ds.XMLID + xmlid := ds.XMLID if ds.ID == nil { t.Error("Cannot clean up Delivery Service with nil ID") return @@ -336,16 +329,16 @@ func cleanUp(t *testing.T, ds tc.DeliveryServiceV4, oldCDNID int, newCDNID int, // BUT, will ALWAYS have nil MaxRequestHeaderBytes. func getCustomDS(cdnID, typeID int, displayName, routingName, orgFQDN, dsID string) tc.DeliveryServiceV4 { customDS := tc.DeliveryServiceV4{} - customDS.Active = util.BoolPtr(true) - customDS.CDNID = util.IntPtr(cdnID) - customDS.DSCP = util.IntPtr(0) - customDS.DisplayName = util.StrPtr(displayName) - customDS.RoutingName = util.StrPtr(routingName) - customDS.GeoLimit = util.IntPtr(0) - customDS.GeoProvider = util.IntPtr(0) - customDS.IPV6RoutingEnabled = util.BoolPtr(false) + customDS.Active = true + customDS.CDNID = cdnID + customDS.DSCP = 0 + customDS.DisplayName = displayName + customDS.RoutingName = routingName + customDS.GeoLimit = 0 + customDS.GeoProvider = 0 + customDS.IPV6RoutingEnabled = false customDS.InitialDispersion = util.IntPtr(1) - customDS.LogsEnabled = util.BoolPtr(true) + customDS.LogsEnabled = true customDS.MissLat = util.FloatPtr(0) customDS.MissLong = util.FloatPtr(0) customDS.MultiSiteOrigin = util.BoolPtr(false) @@ -353,10 +346,10 @@ func getCustomDS(cdnID, typeID int, displayName, routingName, orgFQDN, dsID stri customDS.Protocol = util.IntPtr(2) customDS.QStringIgnore = util.IntPtr(0) customDS.RangeRequestHandling = util.IntPtr(0) - customDS.RegionalGeoBlocking = util.BoolPtr(false) - customDS.TenantID = util.IntPtr(1) - customDS.TypeID = util.IntPtr(typeID) - customDS.XMLID = util.StrPtr(dsID) + customDS.RegionalGeoBlocking = false + customDS.TenantID = 1 + customDS.TypeID = typeID + customDS.XMLID = dsID customDS.MaxRequestHeaderBytes = nil return customDS } @@ -385,9 +378,6 @@ func DeleteCDNOldSSLKeys(t *testing.T) { t.Fatalf("Expected Delivery Service creation to return exactly one Delivery Service, got: %d", len(resp.Response)) } ds := resp.Response[0] - if ds.XMLID == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID") - } ds.CDNName = &cdn.Name sslKeyRequestFields := tc.SSLKeyRequestFields{ @@ -398,9 +388,9 @@ func DeleteCDNOldSSLKeys(t *testing.T) { Country: util.StrPtr("CO"), State: util.StrPtr("ST"), } - genResp, _, err := TOSession.GenerateSSLKeysForDS(*ds.XMLID, *ds.CDNName, sslKeyRequestFields, client.RequestOptions{}) + genResp, _, err := TOSession.GenerateSSLKeysForDS(ds.XMLID, *ds.CDNName, sslKeyRequestFields, client.RequestOptions{}) if err != nil { - t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", *ds.XMLID, err, genResp.Alerts) + t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", ds.XMLID, err, genResp.Alerts) } defer cleanUp(t, ds, cdn.ID, -1, []string{"1"}) @@ -415,15 +405,15 @@ func DeleteCDNOldSSLKeys(t *testing.T) { t.Fatalf("Expected Delivery Service creation to return exactly one Delivery Service, got: %d", len(resp.Response)) } ds2 := resp.Response[0] - if ds2.XMLID == nil || ds2.ID == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID and/or ID") + if ds2.ID == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") } ds2.CDNName = &cdn.Name sslKeyRequestFields.HostName = util.StrPtr("*.test2.com") - genResp, _, err = TOSession.GenerateSSLKeysForDS(*ds2.XMLID, *ds2.CDNName, sslKeyRequestFields, client.RequestOptions{}) + genResp, _, err = TOSession.GenerateSSLKeysForDS(ds2.XMLID, *ds2.CDNName, sslKeyRequestFields, client.RequestOptions{}) if err != nil { - t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", *ds2.XMLID, err, genResp.Alerts) + t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", ds2.XMLID, err, genResp.Alerts) } var cdnKeys []tc.CDNSSLKeys @@ -500,12 +490,9 @@ func DeliveryServiceSSLKeys(t *testing.T) { t.Fatalf("Expected Delivery Service creation to return exactly one Delivery Service, got: %d", len(resp.Response)) } ds := resp.Response[0] - if ds.XMLID == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID") - } ds.CDNName = &cdn.Name - genResp, _, err := TOSession.GenerateSSLKeysForDS(*ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ + genResp, _, err := TOSession.GenerateSSLKeysForDS(ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ BusinessUnit: util.StrPtr("BU"), City: util.StrPtr("CI"), Organization: util.StrPtr("OR"), @@ -514,7 +501,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { State: util.StrPtr("ST"), }, client.RequestOptions{}) if err != nil { - t.Fatalf("Unexpected error generating SSL Keys for Delivery Service '%s': %v - alerts: %+v", *ds.XMLID, err, genResp.Alerts) + t.Fatalf("Unexpected error generating SSL Keys for Delivery Service '%s': %v - alerts: %+v", ds.XMLID, err, genResp.Alerts) } defer cleanUp(t, ds, cdn.ID, -1, []string{"1"}) @@ -522,7 +509,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { for tries := 0; tries < 5; tries++ { time.Sleep(time.Second) var sslKeysResp tc.DeliveryServiceSSLKeysResponse - sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(*ds.XMLID, client.RequestOptions{}) + sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(ds.XMLID, client.RequestOptions{}) *dsSSLKey = sslKeysResp.Response if err == nil && dsSSLKey != nil { break @@ -530,7 +517,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { } if err != nil || dsSSLKey == nil { - t.Fatalf("unable to get DS %v SSL key: %v", *ds.XMLID, err) + t.Fatalf("unable to get DS %v SSL key: %v", ds.XMLID, err) } if dsSSLKey.Certificate.Key == "" { t.Errorf("expected a valid key but got nothing") @@ -570,7 +557,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { for tries := 0; tries < 5; tries++ { time.Sleep(time.Second) var sslKeysResp tc.DeliveryServiceSSLKeysResponse - sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(*ds.XMLID, client.RequestOptions{}) + sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(ds.XMLID, client.RequestOptions{}) *dsSSLKey = sslKeysResp.Response if err == nil && dsSSLKey != nil { break @@ -578,7 +565,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { } if err != nil || dsSSLKey == nil { - t.Fatalf("unable to get DS %v SSL key: %v", *ds.XMLID, err) + t.Fatalf("unable to get DS %v SSL key: %v", ds.XMLID, err) } if dsSSLKey.Certificate.Key == "" { t.Errorf("expected a valid key but got nothing") @@ -617,9 +604,6 @@ func SSLDeliveryServiceCDNUpdateTest(t *testing.T) { t.Fatalf("Expected Delivery Service creation to create exactly one Delivery Service, Traffic Ops indicates %d were created", len(resp.Response)) } ds := resp.Response[0] - if ds.XMLID == nil { - t.Fatal("Traffic Ops created a Delivery Service with no XMLID") - } if ds.ID == nil { t.Fatal("Traffic Ops created a Delivery Service with no ID") } @@ -627,7 +611,7 @@ func SSLDeliveryServiceCDNUpdateTest(t *testing.T) { defer cleanUp(t, ds, oldCdn.ID, newCdn.ID, []string{"1"}) - _, _, err = TOSession.GenerateSSLKeysForDS(*ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ + _, _, err = TOSession.GenerateSSLKeysForDS(ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ BusinessUnit: util.StrPtr("BU"), City: util.StrPtr("CI"), Organization: util.StrPtr("OR"), @@ -660,14 +644,14 @@ func SSLDeliveryServiceCDNUpdateTest(t *testing.T) { t.Fatalf("unable to get cdn %v keys: %v", newCdn.Name, err) } - ds.RoutingName = util.StrPtr("anothername") + ds.RoutingName = "anothername" _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err == nil { t.Fatal("should not be able to update delivery service (routing name) as it has ssl keys") } - ds.RoutingName = util.StrPtr("routingName") + ds.RoutingName = "routingName" - ds.CDNID = &newCdn.ID + ds.CDNID = newCdn.ID ds.CDNName = &newCdn.Name _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err == nil { @@ -728,24 +712,15 @@ func PostDeliveryServiceTest(t *testing.T) { t.Fatal("Need at least one testing Delivery Service to test creating Delivery Services") } ds := testData.DeliveryServices[0] - if ds.XMLID == nil { - t.Fatal("Testing Delivery Service had no XMLID") - } - xmlid := *ds.XMLID + "-topology-test" + xmlid := ds.XMLID + "-topology-test" - ds.XMLID = new(string) _, _, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) if err == nil { t.Error("Expected error with empty xmlid") } - ds.XMLID = nil - _, _, err = TOSession.CreateDeliveryService(ds, client.RequestOptions{}) - if err == nil { - t.Error("Expected error with nil xmlid") - } ds.Topology = new(string) - ds.XMLID = &xmlid + ds.XMLID = xmlid _, reqInf, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) if err == nil { @@ -770,7 +745,7 @@ func CreateTestDeliveryServices(t *testing.T) { ds = ds.RemoveLD1AndLD2() resp, _, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) if err != nil { - t.Errorf("could not create Delivery Service '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) + t.Errorf("could not create Delivery Service '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) } } } @@ -802,25 +777,17 @@ func GetTestDeliveryServices(t *testing.T) { } actualDSMap := make(map[string]tc.DeliveryServiceV4, len(actualDSes.Response)) for _, ds := range actualDSes.Response { - if ds.XMLID == nil { - t.Error("Traffic Ops returned representation of a Delivery Service with null or undefined XMLID") - continue - } - actualDSMap[*ds.XMLID] = ds + actualDSMap[ds.XMLID] = ds } cnt := 0 for _, ds := range testData.DeliveryServices { - if ds.XMLID == nil { - t.Error("Delivery Service found in test data with null or undefined XMLID") - continue - } - if _, ok := actualDSMap[*ds.XMLID]; !ok { - t.Errorf("GET DeliveryService missing: %s", *ds.XMLID) + if _, ok := actualDSMap[ds.XMLID]; !ok { + t.Errorf("GET DeliveryService missing: %s", ds.XMLID) } // exactly one ds should have exactly 3 query params. the rest should have none if c := len(ds.ConsistentHashQueryParams); c > 0 { if c != 3 { - t.Errorf("deliveryservice %s has %d query params; expected 3 or 0", *ds.XMLID, c) + t.Errorf("deliveryservice %s has %d query params; expected 3 or 0", ds.XMLID, c) } cnt++ } @@ -838,11 +805,7 @@ func GetInactiveTestDeliveryServices(t *testing.T) { t.Errorf("cannot get inactive Delivery Services: %v - alerts: %+v", err, inactiveDSes.Alerts) } for _, ds := range inactiveDSes.Response { - if ds.Active == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined 'active'") - continue - } - if *ds.Active != false { + if ds.Active { t.Errorf("expected all delivery services to be inactive, but got atleast one active DS") } } @@ -853,11 +816,7 @@ func GetInactiveTestDeliveryServices(t *testing.T) { t.Errorf("cannot get active Delivery Services: %v - alerts: %+v", err, activeDSes.Alerts) } for _, ds := range activeDSes.Response { - if ds.Active == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined 'active'") - continue - } - if *ds.Active != true { + if !ds.Active { t.Errorf("expected all delivery services to be active, but got atleast one inactive DS") } } @@ -870,18 +829,14 @@ func GetTestDeliveryServicesCapacity(t *testing.T) { } actualDSMap := map[string]tc.DeliveryServiceV4{} for _, ds := range actualDSes.Response { - if ds.XMLID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID") - continue - } if ds.ID == nil { t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") continue } - actualDSMap[*ds.XMLID] = ds + actualDSMap[ds.XMLID] = ds capDS, _, err := TOSession.GetDeliveryServiceCapacity(*ds.ID, client.RequestOptions{}) if err != nil { - t.Errorf(`cannot get Delivery Service "%s"'s (#%d) Capacity: %v - alerts: %+v`, *ds.XMLID, *ds.ID, err, capDS.Alerts) + t.Errorf(`cannot get Delivery Service "%s"'s (#%d) Capacity: %v - alerts: %+v`, ds.XMLID, *ds.ID, err, capDS.Alerts) } } @@ -892,9 +847,6 @@ func UpdateTestDeliveryServices(t *testing.T) { t.Fatal("Need at least one Delivery Service to test updating a Delivery Service") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("Found a Delivery Service in the test data with a null or undefined XMLID") - } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) if err != nil { @@ -904,11 +856,7 @@ func UpdateTestDeliveryServices(t *testing.T) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.XMLID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID") - continue - } - if *ds.XMLID == *firstDS.XMLID { + if ds.XMLID == firstDS.XMLID { found = true remoteDS = ds break @@ -976,9 +924,6 @@ func UpdateNullableTestDeliveryServices(t *testing.T) { t.Fatal("Need at least one Delivery Service to test updating nullable fields of a Delivery Service") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("Found a Delivery Service in the test data with a null or undefined XMLID") - } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) if err != nil { @@ -988,11 +933,11 @@ func UpdateNullableTestDeliveryServices(t *testing.T) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.XMLID == nil || ds.ID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID and/or ID") + if ds.ID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") continue } - if *ds.XMLID == *firstDS.XMLID { + if ds.XMLID == firstDS.XMLID { found = true remoteDS = ds break @@ -1085,8 +1030,8 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { t.Fatalf("expected: 1 DS, actual: %d", len(dses.Response)) } ds := dses.Response[0] - if ds.Topology == nil || ds.ID == nil || ds.XMLID == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined Topology and/or XMLID and/or ID") + if ds.Topology == nil || ds.ID == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined Topology and/or ID") } // unassign its topology, add a required capability that its topology // can't satisfy, then attempt to reassign its topology @@ -1102,7 +1047,7 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { } dsrcResp, _, err := TOSession.CreateDeliveryServicesRequiredCapability(reqCap, client.RequestOptions{}) if err != nil { - t.Fatalf("adding 'asdf' required capability to '%s', expected: no error, actual: %v - alerts: %+v", *ds.XMLID, err, dsrcResp.Alerts) + t.Fatalf("adding 'asdf' required capability to '%s', expected: no error, actual: %v - alerts: %+v", ds.XMLID, err, dsrcResp.Alerts) } ds.Topology = &top _, reqInf, err := TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) @@ -1114,7 +1059,7 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { } dsrcResp, _, err = TOSession.DeleteDeliveryServicesRequiredCapability(*ds.ID, "asdf", client.RequestOptions{}) if err != nil { - t.Fatalf("removing 'asdf' required capability from '%s', expected: no error, actual: %v - alerts: %+v", *ds.XMLID, err, dsrcResp.Alerts) + t.Fatalf("removing 'asdf' required capability from '%s', expected: no error, actual: %v - alerts: %+v", ds.XMLID, err, dsrcResp.Alerts) } _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err != nil { @@ -1144,9 +1089,6 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { t.Fatalf("Expected exactly one Delivery Service to have ID %d, found: %d", *ds.ID, len(resp.Response)) } ds = resp.Response[0] - if ds.CDNID == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined CDN ID") - } const cdn1Name = "cdn1" opts = client.NewRequestOptions() @@ -1176,7 +1118,7 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { if cachegroup.ID == nil { t.Fatalf("Traffic Ops returned a representation for Cache Group '%s' that had null or undefined ID", cacheGroupName) } - opts.QueryParameters = url.Values{"cdn": {strconv.Itoa(*ds.CDNID)}, "cachegroup": {strconv.Itoa(*cachegroup.ID)}} + opts.QueryParameters = url.Values{"cdn": {strconv.Itoa(ds.CDNID)}, "cachegroup": {strconv.Itoa(*cachegroup.ID)}} servers, _, err := TOSession.GetServers(opts) if err != nil { t.Fatalf("getting Server with params %v: %v - alerts: %+v", opts.QueryParameters, err, servers.Alerts) @@ -1231,12 +1173,12 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { ds.Topology = dsTopology _, reqInf, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err == nil { - t.Fatalf("expected 400-level error assigning Topology %s to Delivery Service %s because Cache Group %s has no Servers in it in CDN %d, no error received", *dsTopology, xmlID, cacheGroupName, *ds.CDNID) + t.Fatalf("expected 400-level error assigning Topology %s to Delivery Service %s because Cache Group %s has no Servers in it in CDN %d, no error received", *dsTopology, xmlID, cacheGroupName, ds.CDNID) } if reqInf.StatusCode < http.StatusBadRequest || reqInf.StatusCode >= http.StatusInternalServerError { t.Fatalf("expected %d-level status code but received status code %d", http.StatusBadRequest, reqInf.StatusCode) } - *server.CDNID = *ds.CDNID + *server.CDNID = ds.CDNID *server.ProfileID = profileCopy.ExistingID // Put things back the way they were @@ -1306,9 +1248,6 @@ func UpdateDeliveryServiceWithInvalidRemapText(t *testing.T) { t.Fatal("Need at least one Delivery Service to test updating Delivery Service with invalid remap text") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("Found a Delivery Service in the test data that has null or undefined XMLID") - } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) if err != nil { @@ -1318,18 +1257,18 @@ func UpdateDeliveryServiceWithInvalidRemapText(t *testing.T) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.XMLID == nil || ds.ID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined XMLID and/or ID") + if ds.ID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined ID") continue } - if *ds.XMLID == *firstDS.XMLID { + if ds.XMLID == firstDS.XMLID { found = true remoteDS = ds break } } if !found { - t.Fatalf("GET Delivery Services missing: %s", *firstDS.XMLID) + t.Fatalf("GET Delivery Services missing: %s", firstDS.XMLID) } updatedRemapText := "@plugin=tslua.so @pparam=/opt/trafficserver/etc/trafficserver/remapPlugin1.lua\nline2" @@ -1343,7 +1282,8 @@ func UpdateDeliveryServiceWithInvalidRemapText(t *testing.T) { // UpdateDeliveryServiceWithInvalidSliceRangeRequest ensures that a delivery service can't be updated with a invalid slice range request handler setting. func UpdateDeliveryServiceWithInvalidSliceRangeRequest(t *testing.T) { // GET a HTTP / DNS type DS - var dsXML *string + var dsXML string + found := false for _, ds := range testData.DeliveryServices { if ds.Type == nil { t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined Type") @@ -1351,10 +1291,11 @@ func UpdateDeliveryServiceWithInvalidSliceRangeRequest(t *testing.T) { } if ds.Type.IsDNS() || ds.Type.IsHTTP() { dsXML = ds.XMLID + found = true break } } - if dsXML == nil { + if !found { t.Fatal("no HTTP or DNS Delivery Services to test with") } @@ -1364,20 +1305,20 @@ func UpdateDeliveryServiceWithInvalidSliceRangeRequest(t *testing.T) { } var remoteDS tc.DeliveryServiceV4 - found := false + found = false for _, ds := range dses.Response { - if ds.XMLID == nil || ds.ID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined XMLID and/or ID") + if ds.ID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined ID") continue } - if *ds.XMLID == *dsXML { + if ds.XMLID == dsXML { found = true remoteDS = ds break } } if !found { - t.Fatalf("GET Delivery Services missing: %v", *dsXML) + t.Fatalf("GET Delivery Services missing: %v", dsXML) } testCases := []struct { @@ -1433,13 +1374,13 @@ func UpdateValidateORGServerCacheGroup(t *testing.T) { t.Fatalf("Expected exactly one Delivery Service with the XMLID 'ds-top', found: %d", len(resp.Response)) } remoteDS := resp.Response[0] - if remoteDS.XMLID == nil || remoteDS.ID == nil || remoteDS.Topology == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined XMLID and/or ID and/or Topology") + if remoteDS.ID == nil || remoteDS.Topology == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined ID and/or Topology") } //Assign ORG server to DS assignServer := []string{"denver-mso-org-01"} - alerts, _, err := TOSession.AssignServersToDeliveryService(assignServer, *remoteDS.XMLID, client.RequestOptions{}) + alerts, _, err := TOSession.AssignServersToDeliveryService(assignServer, remoteDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("cannot assign server to Delivery Services: %v - alerts: %+v", err, alerts) } @@ -1555,25 +1496,21 @@ func DeleteTestDeliveryServices(t *testing.T) { t.Errorf("cannot get Delivery Services: %v - alerts: %+v", err, dses.Alerts) } for _, testDS := range testData.DeliveryServices { - if testDS.XMLID == nil { - t.Errorf("testing Delivery Service has no XMLID") - continue - } var ds tc.DeliveryServiceV4 found := false for _, realDS := range dses.Response { - if realDS.XMLID == nil || realDS.ID == nil { - t.Errorf("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID and/or ID") + if realDS.ID == nil { + t.Errorf("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") continue } - if *realDS.XMLID == *testDS.XMLID { + if realDS.XMLID == testDS.XMLID { ds = realDS found = true break } } if !found { - t.Errorf("DeliveryService not found in Traffic Ops: %v", *testDS.XMLID) + t.Errorf("DeliveryService not found in Traffic Ops: %v", testDS.XMLID) continue } @@ -1588,10 +1525,10 @@ func DeleteTestDeliveryServices(t *testing.T) { opts.QueryParameters.Set("id", strconv.Itoa(*ds.ID)) foundDS, _, err := TOSession.GetDeliveryServices(opts) if err != nil { - t.Errorf("Unexpected error deleting Delivery Service '%s': %v - alelts: %+v", *ds.XMLID, err, foundDS.Alerts) + t.Errorf("Unexpected error deleting Delivery Service '%s': %v - alelts: %+v", ds.XMLID, err, foundDS.Alerts) } if len(foundDS.Response) > 0 { - t.Errorf("expected Delivery Service: %s to be deleted, but %d exist with same ID (#%d)", *ds.XMLID, len(foundDS.Response), *ds.ID) + t.Errorf("expected Delivery Service: %s to be deleted, but %d exist with same ID (#%d)", ds.XMLID, len(foundDS.Response), *ds.ID) } } @@ -1615,11 +1552,8 @@ func DeliveryServiceMinorVersionsTest(t *testing.T) { t.Fatalf("Need at least 5 DSes to test minor versions; got: %d", len(testData.DeliveryServices)) } testDS := testData.DeliveryServices[4] - if testDS.XMLID == nil { - t.Fatal("expected XMLID: ds-test-minor-versions, actual: ") - } - if *testDS.XMLID != "ds-test-minor-versions" { - t.Errorf("expected XMLID: ds-test-minor-versions, actual: %s", *testDS.XMLID) + if testDS.XMLID != "ds-test-minor-versions" { + t.Errorf("expected XMLID: ds-test-minor-versions, actual: %s", testDS.XMLID) } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) @@ -1630,20 +1564,18 @@ func DeliveryServiceMinorVersionsTest(t *testing.T) { var ds tc.DeliveryServiceV4 found := false for _, d := range dses.Response { - if d.XMLID != nil && *d.XMLID == *testDS.XMLID { + if d.XMLID == testDS.XMLID { ds = d found = true break } } if !found { - t.Fatalf("Delivery Service '%s' not found in Traffic Ops", *testDS.XMLID) + t.Fatalf("Delivery Service '%s' not found in Traffic Ops", testDS.XMLID) } // GET latest, verify expected values for 1.3 and 1.4 fields - if ds.DeepCachingType == nil { - t.Errorf("expected DeepCachingType: %s, actual: nil", testDS.DeepCachingType.String()) - } else if *ds.DeepCachingType != *testDS.DeepCachingType { + if ds.DeepCachingType != testDS.DeepCachingType { t.Errorf("expected DeepCachingType: %s, actual: %s", testDS.DeepCachingType.String(), ds.DeepCachingType.String()) } if ds.FQPacingRate == nil { @@ -1703,11 +1635,11 @@ func DeliveryServiceTenancyTest(t *testing.T) { var tenant3DS tc.DeliveryServiceV4 foundTenant3DS := false for _, d := range dses.Response { - if d.XMLID == nil || d.ID == nil || d.Tenant == nil { - t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID and/or ID and/or Tenant") + if d.ID == nil || d.Tenant == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined ID and/or Tenant") continue } - if *d.XMLID == "ds3" { + if d.XMLID == "ds3" { tenant3DS = d foundTenant3DS = true } @@ -1729,28 +1661,24 @@ func DeliveryServiceTenancyTest(t *testing.T) { // assert that tenant4user cannot read deliveryservices outside of its tenant for _, ds := range dsesReadableByTenant4.Response { - if ds.XMLID == nil { - t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID") - continue - } - if *ds.XMLID == "ds3" { + if ds.XMLID == "ds3" { t.Error("expected tenant4 to be unable to read delivery services from tenant 3") } } // assert that tenant4user cannot update tenant3user's deliveryservice if _, _, err = tenant4TOClient.UpdateDeliveryService(*tenant3DS.ID, tenant3DS, client.RequestOptions{}); err == nil { - t.Errorf("expected tenant4user to be unable to update tenant3's deliveryservice (%s)", *tenant3DS.XMLID) + t.Errorf("expected tenant4user to be unable to update tenant3's deliveryservice (%s)", tenant3DS.XMLID) } // assert that tenant4user cannot delete tenant3user's deliveryservice if _, _, err = tenant4TOClient.DeleteDeliveryService(*tenant3DS.ID, client.RequestOptions{}); err == nil { - t.Errorf("expected tenant4user to be unable to delete tenant3's deliveryservice (%s)", *tenant3DS.XMLID) + t.Errorf("expected tenant4user to be unable to delete tenant3's deliveryservice (%s)", tenant3DS.XMLID) } // assert that tenant4user cannot create a deliveryservice outside of its tenant - tenant3DS.XMLID = util.StrPtr("deliveryservicetenancytest") - tenant3DS.DisplayName = util.StrPtr("deliveryservicetenancytest") + tenant3DS.XMLID = "deliveryservicetenancytest" + tenant3DS.DisplayName = "deliveryservicetenancytest" if _, _, err = tenant4TOClient.CreateDeliveryService(tenant3DS, client.RequestOptions{}); err == nil { t.Error("expected tenant4user to be unable to create a deliveryservice outside of its tenant") } @@ -1833,27 +1761,24 @@ func GetDeliveryServiceByCdn(t *testing.T) { } opts := client.NewRequestOptions() - if firstDS.CDNID == nil { - opts.QueryParameters.Set("name", *firstDS.CDNName) - cdns, _, err := TOSession.GetCDNs(opts) - if err != nil { - t.Errorf("Unexpected error getting CDN '%s' by name: %v - alerts: %+v", *firstDS.CDNName, err, cdns.Alerts) - } - if len(cdns.Response) != 1 { - t.Fatalf("Expected exactly one CDN named '%s' to exist, found: %d", *firstDS.CDNName, len(cdns.Response)) - } - firstDS.CDNID = new(int) - *firstDS.CDNID = cdns.Response[0].ID - opts.QueryParameters.Del("name") + opts.QueryParameters.Set("name", *firstDS.CDNName) + cdns, _, err := TOSession.GetCDNs(opts) + if err != nil { + t.Errorf("Unexpected error getting CDN '%s' by name: %v - alerts: %+v", *firstDS.CDNName, err, cdns.Alerts) + } + if len(cdns.Response) != 1 { + t.Fatalf("Expected exactly one CDN named '%s' to exist, found: %d", *firstDS.CDNName, len(cdns.Response)) } + firstDS.CDNID = cdns.Response[0].ID + opts.QueryParameters.Del("name") - opts.QueryParameters.Set("cdn", strconv.Itoa(*firstDS.CDNID)) + opts.QueryParameters.Set("cdn", strconv.Itoa(firstDS.CDNID)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by CDN ID: %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Delivery Service to exist in CDN '%s' (#%d)", *firstDS.CDNName, *firstDS.CDNID) + t.Fatalf("Expected at least one Delivery Service to exist in CDN '%s' (#%d)", *firstDS.CDNName, firstDS.CDNID) } if resp.Response[0].CDNName == nil { t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined CDN Name") @@ -1940,13 +1865,10 @@ func GetTestDeliveryServicesURLSignatureKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("couldn't get the xml ID of test DS") - } - _, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) + _, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { - t.Error("failed to get url sig keys: " + err.Error()) + t.Errorf("failed to get url sig keys: %v", err) } } @@ -1955,15 +1877,12 @@ func CreateTestDeliveryServicesURLSignatureKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("couldn't get the xml ID of test DS") - } - resp, _, err := TOSession.CreateDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) + resp, _, err := TOSession.CreateDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error creaetting URL signing keys: %v - alerts: %+v", err, resp.Alerts) } - firstKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) + firstKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error getting URL signing keys: %v - alerts: %+v", err, firstKeys.Alerts) } @@ -1976,11 +1895,11 @@ func CreateTestDeliveryServicesURLSignatureKeys(t *testing.T) { } // Create new keys again and check that they are different - resp, _, err = TOSession.CreateDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) + resp, _, err = TOSession.CreateDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error creating URL signing keys: %v - alerts: %+v", err, resp.Alerts) } - secondKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) + secondKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error getting URL signing keys: %v - alerts: %+v", err, secondKeys.Alerts) } @@ -2002,11 +1921,8 @@ func DeleteTestDeliveryServicesURLSignatureKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("couldn't get the xml ID of test DS") - } - resp, _, err := TOSession.DeleteDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) + resp, _, err := TOSession.DeleteDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error deletining URL signing keys: %v - alerts: %+v", err, resp.Alerts) } @@ -2018,13 +1934,10 @@ func GetTestDeliveryServicesURISigningKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("couldn't get the xml ID of test DS") - } - _, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) + _, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", *firstDS.XMLID, err) + t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", firstDS.XMLID, err) } } @@ -2064,9 +1977,6 @@ func CreateTestDeliveryServicesURISigningKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("couldn't get the xml ID of test DS") - } var keyset map[string]tc.URISignerKeyset @@ -2074,12 +1984,12 @@ func CreateTestDeliveryServicesURISigningKeys(t *testing.T) { t.Errorf("json.UnMarshal(): expected nil error, actual: %v", err) } - _, _, err := TOSession.CreateDeliveryServiceURISigningKeys(*firstDS.XMLID, keyset, client.RequestOptions{}) + _, _, err := TOSession.CreateDeliveryServiceURISigningKeys(firstDS.XMLID, keyset, client.RequestOptions{}) if err != nil { t.Error("failed to create uri sig keys: " + err.Error()) } - firstKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) + firstKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Error("failed to get uri sig keys: " + err.Error()) } @@ -2104,12 +2014,12 @@ func CreateTestDeliveryServicesURISigningKeys(t *testing.T) { t.Errorf("json.UnMarshal(): expected nil error, actual: %v", err) } - alerts, _, err := TOSession.CreateDeliveryServiceURISigningKeys(*firstDS.XMLID, keyset2, client.RequestOptions{}) + alerts, _, err := TOSession.CreateDeliveryServiceURISigningKeys(firstDS.XMLID, keyset2, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error creating URI Signature Keys for Delivery Service '%s': %v - alerts: %+v", *firstDS.XMLID, err, alerts.Alerts) + t.Errorf("Unexpected error creating URI Signature Keys for Delivery Service '%s': %v - alerts: %+v", firstDS.XMLID, err, alerts.Alerts) } - secondKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) + secondKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Error("failed to get uri sig keys: " + err.Error()) } @@ -2137,13 +2047,10 @@ func DeleteTestDeliveryServicesURISigningKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Fatal("couldn't get the xml ID of test DS") - } - resp, _, err := TOSession.DeleteDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) + resp, _, err := TOSession.DeleteDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error deleting URI Signing keys for Delivery Service '%s': %v - alerts: %+v", *firstDS.XMLID, err, resp.Alerts) + t.Errorf("Unexpected error deleting URI Signing keys for Delivery Service '%s': %v - alerts: %+v", firstDS.XMLID, err, resp.Alerts) } emptyBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) @@ -2176,24 +2083,18 @@ func GetDeliveryServiceByLogsEnabled(t *testing.T) { t.Fatal("Need at least one Delivery Service to test getting Delivery Services filtered by their Logs Enabled property") } firstDS := testData.DeliveryServices[0] - if firstDS.LogsEnabled == nil { - t.Fatal("Logs Enabled is nil in the pre-requisites ") - } opts := client.NewRequestOptions() - opts.QueryParameters.Set("logsEnabled", strconv.FormatBool(*firstDS.LogsEnabled)) + opts.QueryParameters.Set("logsEnabled", strconv.FormatBool(firstDS.LogsEnabled)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by 'logsEnabled': %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Delivery Service to exist with Logs Enabled set to %t", *firstDS.LogsEnabled) + t.Fatalf("Expected at least one Delivery Service to exist with Logs Enabled set to %t", firstDS.LogsEnabled) } - if resp.Response[0].LogsEnabled == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined Logs Enabled property") - } - if *resp.Response[0].LogsEnabled != *firstDS.LogsEnabled { - t.Errorf("Logs enabled status expected: %t, actual: %t", *firstDS.LogsEnabled, *resp.Response[0].LogsEnabled) + if resp.Response[0].LogsEnabled != firstDS.LogsEnabled { + t.Errorf("Logs enabled status expected: %t, actual: %t", firstDS.LogsEnabled, resp.Response[0].LogsEnabled) } } @@ -2249,21 +2150,18 @@ func GetDeliveryServiceByValidTenant(t *testing.T) { } opts := client.NewRequestOptions() - if firstDS.TenantID == nil { - opts.QueryParameters.Set("name", *firstDS.Tenant) - tenants, _, err := TOSession.GetTenants(opts) - if err != nil { - t.Errorf("Unexpected error getting Tenants filtered by name: %v - alerts: %+v", err, tenants.Alerts) - } - if len(tenants.Response) != 1 { - t.Fatalf("Expected exactly one Tenant to exist with name '%s', found %d:", *firstDS.Tenant, len(tenants.Response)) - } - firstDS.TenantID = new(int) - *firstDS.TenantID = tenants.Response[0].ID - opts.QueryParameters.Del("name") + opts.QueryParameters.Set("name", *firstDS.Tenant) + tenants, _, err := TOSession.GetTenants(opts) + if err != nil { + t.Errorf("Unexpected error getting Tenants filtered by name: %v - alerts: %+v", err, tenants.Alerts) } + if len(tenants.Response) != 1 { + t.Fatalf("Expected exactly one Tenant to exist with name '%s', found %d:", *firstDS.Tenant, len(tenants.Response)) + } + firstDS.TenantID = tenants.Response[0].ID + opts.QueryParameters.Del("name") - opts.QueryParameters.Set("tenant", strconv.Itoa(*firstDS.TenantID)) + opts.QueryParameters.Set("tenant", strconv.Itoa(firstDS.TenantID)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by Tenant ID: %v - alerts: %+v", err, resp.Alerts) @@ -2289,27 +2187,24 @@ func GetDeliveryServiceByValidType(t *testing.T) { } opts := client.NewRequestOptions() - if firstDS.TypeID == nil { - opts.QueryParameters.Set("name", firstDS.Type.String()) - types, _, err := TOSession.GetTypes(opts) - if err != nil { - t.Errorf("Unexpected error getting Types filtered by name: %v - alerts: %+v", err, types.Alerts) - } - if len(types.Response) != 1 { - t.Fatalf("Expected exactly one Type to exist with name '%s', found %d:", *firstDS.Type, len(types.Response)) - } - firstDS.TypeID = new(int) - *firstDS.TypeID = types.Response[0].ID - opts.QueryParameters.Del("name") + opts.QueryParameters.Set("name", firstDS.Type.String()) + types, _, err := TOSession.GetTypes(opts) + if err != nil { + t.Errorf("Unexpected error getting Types filtered by name: %v - alerts: %+v", err, types.Alerts) + } + if len(types.Response) != 1 { + t.Fatalf("Expected exactly one Type to exist with name '%s', found %d:", *firstDS.Type, len(types.Response)) } + firstDS.TypeID = types.Response[0].ID + opts.QueryParameters.Del("name") - opts.QueryParameters.Set("type", strconv.Itoa(*firstDS.TypeID)) + opts.QueryParameters.Set("type", strconv.Itoa(firstDS.TypeID)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by Type ID: %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Delivery Service to exist with Type '%s' (#%d)", *firstDS.Type, *firstDS.TypeID) + t.Fatalf("Expected at least one Delivery Service to exist with Type '%s' (#%d)", *firstDS.Type, firstDS.TypeID) } if resp.Response[0].Type == nil { t.Fatal("Traffic Ops returned a representation of a Delivery Service with null or undefined Type Name") @@ -2324,24 +2219,18 @@ func GetDeliveryServiceByValidXmlId(t *testing.T) { t.Fatal("Need at least one Delivery Service to test getting Delivery Services filtered by XMLID") } firstDS := testData.DeliveryServices[0] - if firstDS.XMLID == nil { - t.Errorf("XML ID is nil in the Pre-requisites") - } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", *firstDS.XMLID) + opts.QueryParameters.Set("xmlId", firstDS.XMLID) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by XMLID: %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) != 1 { - t.Fatalf("Expected exactly one Delivery Service to exist with XMLID '%s', found: %d", *firstDS.XMLID, len(resp.Response)) - } - if resp.Response[0].XMLID == nil { - t.Fatal("Traffic Ops returned a representation of a Delivery Service with null or undefined XMLID") + t.Fatalf("Expected exactly one Delivery Service to exist with XMLID '%s', found: %d", firstDS.XMLID, len(resp.Response)) } - if *resp.Response[0].XMLID != *firstDS.XMLID { - t.Errorf("Delivery Service XMLID expected: %s, actual: %s", *firstDS.XMLID, *resp.Response[0].XMLID) + if resp.Response[0].XMLID != firstDS.XMLID { + t.Errorf("Delivery Service XMLID expected: %s, actual: %s", firstDS.XMLID, resp.Response[0].XMLID) } } @@ -2373,9 +2262,7 @@ func SortTestDeliveryServicesDesc(t *testing.T) { for start, end := 0, len(respDesc)-1; start < end; start, end = start+1, end-1 { respDesc[start], respDesc[end] = respDesc[end], respDesc[start] } - if respDesc[0].XMLID != nil && respAsc[0].XMLID != nil { - if !reflect.DeepEqual(respDesc[0].XMLID, respAsc[0].XMLID) { - t.Errorf("Delivery Service responses are not equal after reversal: %v - %v", *respDesc[0].XMLID, *respAsc[0].XMLID) - } + if !reflect.DeepEqual(respDesc[0].XMLID, respAsc[0].XMLID) { + t.Errorf("Delivery Service responses are not equal after reversal: %v - %v", respDesc[0].XMLID, respAsc[0].XMLID) } } diff --git a/traffic_ops/testing/api/v4/deliveryserviceservers_test.go b/traffic_ops/testing/api/v4/deliveryserviceservers_test.go index 72f0dc6082..e074959545 100644 --- a/traffic_ops/testing/api/v4/deliveryserviceservers_test.go +++ b/traffic_ops/testing/api/v4/deliveryserviceservers_test.go @@ -229,13 +229,13 @@ func AssignServersToTopologyBasedDeliveryService(t *testing.T) { t.Fatalf("expected one delivery service: 'ds-top', actual: %v", len(ds.Response)) } d := ds.Response[0] - if d.Topology == nil || d.ID == nil || d.CDNID == nil || d.CDNName == nil { - t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or CDN ID and/or CDN Name and/or ID") + if d.Topology == nil || d.ID == nil || d.CDNName == nil { + t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or CDN Name and/or ID") } serversResp, _, err := TOSession.GetServers(client.RequestOptions{}) servers := []tc.ServerV4{} for _, s := range serversResp.Response { - if s.CDNID != nil && *s.CDNID == *d.CDNID && s.Type == tc.CacheTypeEdge.String() { + if s.CDNID != nil && *s.CDNID == d.CDNID && s.Type == tc.CacheTypeEdge.String() { servers = append(servers, s) } } @@ -247,7 +247,7 @@ func AssignServersToTopologyBasedDeliveryService(t *testing.T) { } serverNames := []string{} for _, s := range servers { - if s.CDNID != nil && s.HostName != nil && *s.CDNID == *d.CDNID && s.Type == tc.CacheTypeEdge.String() { + if s.CDNID != nil && s.HostName != nil && *s.CDNID == d.CDNID && s.Type == tc.CacheTypeEdge.String() { serverNames = append(serverNames, *s.HostName) } else { t.Fatalf("expected only EDGE servers in cdn '%s', actual: %v", *d.CDNName, servers) @@ -353,8 +353,8 @@ func AssignServersToNonTopologyBasedDeliveryServiceThatUsesMidTier(t *testing.T) if dsWithMid.Topology != nil { t.Fatal("expected delivery service: 'ds1' to have a nil Topology, actual: non-nil") } - if dsWithMid.CDNID == nil || dsWithMid.CDNName == nil || dsWithMid.ID == nil { - t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined CDN ID and/or CDN Name and/or ID") + if dsWithMid.CDNName == nil || dsWithMid.ID == nil { + t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined CDN Name and/or ID") } serversResp, _, err := TOSession.GetServers(client.RequestOptions{}) if err != nil { @@ -362,7 +362,7 @@ func AssignServersToNonTopologyBasedDeliveryServiceThatUsesMidTier(t *testing.T) } serversIds := []int{} for _, s := range serversResp.Response { - if s.CDNID != nil && *s.CDNID == *dsWithMid.CDNID && s.Type == tc.CacheTypeEdge.String() { + if s.CDNID != nil && *s.CDNID == dsWithMid.CDNID && s.Type == tc.CacheTypeEdge.String() { serversIds = append(serversIds, *s.ID) } } @@ -389,7 +389,7 @@ func AssignServersToNonTopologyBasedDeliveryServiceThatUsesMidTier(t *testing.T) } for _, dss := range dsServersResp.Response { - if dss.CDNID != nil && *dss.CDNID != *dsWithMid.CDNID { + if dss.CDNID != nil && *dss.CDNID != dsWithMid.CDNID { t.Fatalf("a server for another cdn was returned for this delivery service") } } @@ -580,9 +580,6 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { if ds.ID == nil { t.Fatalf("Got a delivery service with a nil ID %+v", ds) } - if ds.Active == nil { - t.Fatalf("Got a Delivery Service with nil 'Active': %+v", ds) - } resp, _, err := TOSession.CreateDeliveryServiceServers(*ds.ID, []int{*server.ID}, true, client.RequestOptions{}) if err != nil { @@ -605,8 +602,8 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { t.Error("POST delivery service servers returned success, but ds-server not in GET") } - if *ds.Active { - *ds.Active = false + if ds.Active { + ds.Active = false _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err != nil { t.Errorf("Setting Delivery Service #%d to inactive", *ds.ID) diff --git a/traffic_ops/testing/api/v4/federations_test.go b/traffic_ops/testing/api/v4/federations_test.go index 071bb3dc74..60f8d6e1ce 100644 --- a/traffic_ops/testing/api/v4/federations_test.go +++ b/traffic_ops/testing/api/v4/federations_test.go @@ -223,14 +223,14 @@ func AddFederationResolversForCurrentUserTest(t *testing.T) { mappings := tc.DeliveryServiceFederationResolverMappingRequest{ tc.DeliveryServiceFederationResolverMapping{ - DeliveryService: *ds.XMLID, + DeliveryService: ds.XMLID, Mappings: tc.ResolverMapping{ Resolve4: []string{"0.0.0.0"}, Resolve6: []string{"::1"}, }, }, tc.DeliveryServiceFederationResolverMapping{ - DeliveryService: *ds1.XMLID, + DeliveryService: ds1.XMLID, Mappings: tc.ResolverMapping{ Resolve4: []string{"1.2.3.4/28"}, Resolve6: []string{"1234::/110"}, diff --git a/traffic_ops/testing/api/v4/jobs_test.go b/traffic_ops/testing/api/v4/jobs_test.go index 9c41b6b25b..c560c1e6cf 100644 --- a/traffic_ops/testing/api/v4/jobs_test.go +++ b/traffic_ops/testing/api/v4/jobs_test.go @@ -71,10 +71,7 @@ func JobCollisionWarningTest(t *testing.T) { if len(testData.DeliveryServices) < 1 { t.Fatal("Need at least one Delivery Service to test Invalidation Job collisions") } - if testData.DeliveryServices[0].XMLID == nil { - t.Fatal("Found a Delivery Service in the testing data with null or undefined XMLID") - } - xmlID := *testData.DeliveryServices[0].XMLID + xmlID := testData.DeliveryServices[0].XMLID startTime := tc.Time{ Time: time.Now().Add(time.Hour), @@ -175,11 +172,11 @@ func CreateTestInvalidationJobs(t *testing.T) { } dsNameIDs := make(map[string]int64, len(toDSes.Response)) for _, ds := range toDSes.Response { - if ds.XMLID == nil || ds.ID == nil { - t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID and/or ID") + if ds.ID == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined ID") continue } - dsNameIDs[*ds.XMLID] = int64(*ds.ID) + dsNameIDs[ds.XMLID] = int64(*ds.ID) } for _, job := range testData.InvalidationJobs { @@ -203,11 +200,11 @@ func CreateTestInvalidJob(t *testing.T) { } dsNameIDs := make(map[string]int64, len(toDSes.Response)) for _, ds := range toDSes.Response { - if ds.XMLID == nil || ds.ID == nil { + if ds.ID == nil { t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID and/or ID") continue } - dsNameIDs[*ds.XMLID] = int64(*ds.ID) + dsNameIDs[ds.XMLID] = int64(*ds.ID) } if len(testData.InvalidationJobs) < 1 { diff --git a/traffic_ops/testing/api/v4/servers_test.go b/traffic_ops/testing/api/v4/servers_test.go index ddc1c126b6..a3f7ba6298 100644 --- a/traffic_ops/testing/api/v4/servers_test.go +++ b/traffic_ops/testing/api/v4/servers_test.go @@ -593,11 +593,11 @@ func GetTestServersQueryParameters(t *testing.T) { topology = "mso-topology" ) for _, ds = range dses.Response { - if ds.XMLID == nil || ds.ID == nil { - t.Error("Traffic Ops returned a representation of a Delivery Service that had a null or undefined XMLID and/or ID") + if ds.ID == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service that had a null or undefined ID") continue } - if *ds.XMLID != topDSXmlID { + if ds.XMLID != topDSXmlID { continue } if ds.Topology == nil || ds.FirstHeaderRewrite == nil || ds.InnerHeaderRewrite == nil || ds.LastHeaderRewrite == nil { diff --git a/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go b/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go index 66676db948..4c6490890e 100644 --- a/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go +++ b/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go @@ -56,12 +56,8 @@ func AssignTestDeliveryService(t *testing.T) { t.Fatalf("Server '%s' had nil ID", *server.HostName) } - if testData.DeliveryServices[0].XMLID == nil { - t.Fatal("Found Delivery Service in testing data with null or undefined XMLID") - } - opts.QueryParameters.Del("hostName") - opts.QueryParameters.Set("xmlId", *testData.DeliveryServices[0].XMLID) + opts.QueryParameters.Set("xmlId", testData.DeliveryServices[0].XMLID) rd, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Fatalf("Failed to fetch DS information: %v - alerts: %+v", err, rd.Alerts) @@ -138,12 +134,9 @@ func AssignIncorrectTestDeliveryService(t *testing.T) { if len(testData.DeliveryServices) < 1 { t.Fatal("Need at least one Delivery Service to test assignment of servers to Delivery Services") } - if testData.DeliveryServices[0].XMLID == nil { - t.Fatal("Delivery Service selected for testing had null or undefined XMLID") - } opts = client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", *testData.DeliveryServices[0].XMLID) + opts.QueryParameters.Set("xmlId", testData.DeliveryServices[0].XMLID) rd, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Fatalf("Failed to fetch DS information: %v - alerts: %+v", err, rd.Alerts) diff --git a/traffic_ops/testing/api/v4/tenants_test.go b/traffic_ops/testing/api/v4/tenants_test.go index 3c649ffa2c..81be79af2f 100644 --- a/traffic_ops/testing/api/v4/tenants_test.go +++ b/traffic_ops/testing/api/v4/tenants_test.go @@ -286,13 +286,6 @@ func DeleteTestTenants(t *testing.T) { } } -func ExtractXMLID(ds *tc.DeliveryServiceV4) string { - if ds.XMLID != nil { - return *ds.XMLID - } - return "nil" -} - func UpdateTestTenantsActive(t *testing.T) { originalTenants, _, err := TOSession.GetTenants(client.RequestOptions{}) if err != nil { @@ -340,7 +333,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds3': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 parent tenant2 is inactive, expected: no ds", ExtractXMLID(&ds)) + t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 parent tenant2 is inactive, expected: no ds", ds.XMLID) } setTenantActive(t, "tenant1", true) @@ -353,7 +346,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds3': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 is inactive, expected: no ds", ExtractXMLID(&ds)) + t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 is inactive, expected: no ds", ds.XMLID) } setTenantActive(t, "tenant1", true) @@ -378,7 +371,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds2': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user got delivery service %s with tenant2, expected: no ds", ExtractXMLID(&ds)) + t.Errorf("tenant3user got delivery service %s with tenant2, expected: no ds", ds.XMLID) } // 1. ds1 has tenant1. @@ -391,7 +384,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds1': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant4user got delivery service %s with tenant1, expected: no ds", ExtractXMLID(&ds)) + t.Errorf("tenant4user got delivery service %s with tenant1, expected: no ds", ds.XMLID) } setTenantActive(t, "tenant3", false) @@ -401,7 +394,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds3': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user was inactive, but got delivery service %s with tenant3, expected: no ds", ExtractXMLID(&ds)) + t.Errorf("tenant3user was inactive, but got delivery service %s with tenant3, expected: no ds", ds.XMLID) } for _, tn := range originalTenants.Response { diff --git a/traffic_ops/testing/api/v4/topologies_queue_update_test.go b/traffic_ops/testing/api/v4/topologies_queue_update_test.go index 577bb045d0..0c1db6b42e 100644 --- a/traffic_ops/testing/api/v4/topologies_queue_update_test.go +++ b/traffic_ops/testing/api/v4/topologies_queue_update_test.go @@ -56,10 +56,10 @@ func getCDNIDAndDSID(t *testing.T) (int64, int) { t.Fatalf("deliveryservice with xmlId '%s' not found!", xmlID) } ds := dses.Response[0] - if ds.CDNID == nil || ds.ID == nil { - t.Fatalf("Traffic Ops returned a representation of a Delivery Service that had null or undefined CDN ID and/or ID") + if ds.ID == nil { + t.Fatalf("Traffic Ops returned a representation of a Delivery Service that had null or undefined ID") } - return int64(*ds.CDNID), *ds.ID + return int64(ds.CDNID), *ds.ID } func InvalidCDNIDIsRejected(t *testing.T, topologyName string) { diff --git a/traffic_ops/testing/api/v4/topologies_test.go b/traffic_ops/testing/api/v4/topologies_test.go index a280ecf2fa..470d57a61a 100644 --- a/traffic_ops/testing/api/v4/topologies_test.go +++ b/traffic_ops/testing/api/v4/topologies_test.go @@ -353,15 +353,15 @@ func UpdateValidateTopologyORGServerCacheGroup(t *testing.T) { t.Fatalf("Expected exactly one Delivery Service to exist with XMLID 'ds-top', found: %d", len(resp.Response)) } remoteDS := resp.Response[0] - if remoteDS.XMLID == nil || remoteDS.Topology == nil || remoteDS.ID == nil { - t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or XMLID and/or ID") + if remoteDS.Topology == nil || remoteDS.ID == nil { + t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or ID") } //Assign ORG server to DS assignServer := []string{"denver-mso-org-01"} - assignResponse, _, err := TOSession.AssignServersToDeliveryService(assignServer, *remoteDS.XMLID, toclient.RequestOptions{}) + assignResponse, _, err := TOSession.AssignServersToDeliveryService(assignServer, remoteDS.XMLID, toclient.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error assigning server 'denver-mso-org-01' to Delivery Service '%s': %v - alerts: %+v", *remoteDS.XMLID, err, assignResponse.Alerts) + t.Errorf("Unexpected error assigning server 'denver-mso-org-01' to Delivery Service '%s': %v - alerts: %+v", remoteDS.XMLID, err, assignResponse.Alerts) } //Get Topology node to update and remove ORG server nodes diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go index 2f84ba2e1a..0f50f9ac89 100644 --- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go +++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go @@ -925,8 +925,8 @@ func CheckTopology(tx *sqlx.Tx, ds tc.DeliveryServiceV4) (int, error, error) { return http.StatusBadRequest, fmt.Errorf("no such Topology '%s'", *ds.Topology), nil } - if err = topology_validation.CheckForEmptyCacheGroups(tx, cacheGroupIDs, []int{*ds.CDNID}, true, []int{}); err != nil { - return http.StatusBadRequest, fmt.Errorf("empty cachegroups in Topology %s found for CDN %d: %s", *ds.Topology, *ds.CDNID, err.Error()), nil + if err = topology_validation.CheckForEmptyCacheGroups(tx, cacheGroupIDs, []int{ds.CDNID}, true, []int{}); err != nil { + return http.StatusBadRequest, fmt.Errorf("empty cachegroups in Topology %s found for CDN %d: %w", *ds.Topology, ds.CDNID, err), nil } return statusCode, userErr, sysErr diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 68ad7894a7..ea8e20cfb1 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -95,10 +95,7 @@ func (ds TODeliveryService) GetKeyFieldsInfo() []api.KeyFieldInfo { } func (ds *TODeliveryService) GetAuditName() string { - if ds.XMLID != nil { - return *ds.XMLID - } - return "" + return ds.XMLID } func (ds *TODeliveryService) GetType() string { @@ -320,7 +317,7 @@ func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 t } } - if err := EnsureCacheURLParams(tx, *ds.ID, *ds.XMLID, dsV31.CacheURL); err != nil { + if err := EnsureCacheURLParams(tx, *ds.ID, ds.XMLID, dsV31.CacheURL); err != nil { return nil, http.StatusInternalServerError, nil, err } @@ -346,10 +343,7 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t } // TODO change DeepCachingType to implement sql.Valuer and sql.Scanner, so sqlx struct scan can be used. - deepCachingType := tc.DeepCachingType("").String() - if ds.DeepCachingType != nil { - deepCachingType = ds.DeepCachingType.String() // necessary, because DeepCachingType's default needs to insert the string, not "", and Query doesn't call .String(). - } + 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 @@ -488,7 +482,7 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t defer resultRows.Close() id := 0 - lastUpdated := tc.TimeNoMod{} + var lastUpdated time.Time if !resultRows.Next() { return nil, http.StatusInternalServerError, nil, errors.New("no deliveryservice request inserted, no id was returned") } @@ -503,19 +497,13 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t if ds.ID == nil { return nil, http.StatusInternalServerError, nil, errors.New("missing id after insert") } - if ds.XMLID == nil { - return nil, http.StatusInternalServerError, nil, errors.New("missing xml_id after insert") - } - if ds.TypeID == nil { - return nil, http.StatusInternalServerError, nil, errors.New("missing type after insert") - } - dsType, err := getTypeFromID(*ds.TypeID, tx) + dsType, err := getTypeFromID(ds.TypeID, tx) if err != nil { return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type: " + err.Error()) } ds.Type = &dsType - if err := createDefaultRegex(tx, *ds.ID, *ds.XMLID); err != nil { + if err := createDefaultRegex(tx, *ds.ID, ds.XMLID); err != nil { return nil, http.StatusInternalServerError, nil, errors.New("creating default regex: " + err.Error()) } @@ -524,14 +512,14 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t return nil, code, usrErr, sysErr } - matchlists, err := GetDeliveryServicesMatchLists([]string{*ds.XMLID}, tx) + matchlists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx) if err != nil { return nil, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: " + err.Error()) } - if matchlist, ok := matchlists[*ds.XMLID]; !ok { + if matchlist, ok := matchlists[ds.XMLID]; !ok { return nil, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: not found") } else { - ds.MatchList = &matchlist + ds.MatchList = matchlist } cdnName, cdnDomain, dnssecEnabled, err := getCDNNameDomainDNSSecEnabled(*ds.ID, tx) @@ -539,9 +527,9 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t return nil, http.StatusInternalServerError, nil, errors.New("creating DS: getting CDN info: " + err.Error()) } - ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *ds.Type, *ds.RoutingName, *ds.MatchList, cdnDomain) + ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *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 { + 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, errors.New("ensuring ds parameters:: " + err.Error()) } @@ -549,7 +537,7 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t 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 { + if userErr, sysErr, statusCode := PutDNSSecKeys(tx, ds.XMLID, cdnName, ds.ExampleURLs, inf.Vault, r.Context()); userErr != nil || sysErr != nil { return nil, statusCode, userErr, sysErr } } @@ -558,8 +546,8 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t return nil, http.StatusInternalServerError, nil, errors.New("creating delivery service: " + err.Error()) } - 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 { + 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, errors.New("error writing to audit log: " + err.Error()) } @@ -972,7 +960,7 @@ func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 * } } - if err := EnsureCacheURLParams(tx, *ds.ID, *ds.XMLID, dsV31.CacheURL); err != nil { + if err := EnsureCacheURLParams(tx, *ds.ID, ds.XMLID, dsV31.CacheURL); err != nil { return nil, http.StatusInternalServerError, nil, err } @@ -995,16 +983,13 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * return nil, http.StatusForbidden, errors.New("not authorized on this tenant"), nil } - if ds.XMLID == nil { - return nil, http.StatusBadRequest, errors.New("missing xml_id"), nil - } if ds.ID == nil { return nil, http.StatusBadRequest, errors.New("missing id"), nil } - dsType, ok, err := getDSType(tx, *ds.XMLID) + dsType, ok, err := getDSType(tx, ds.XMLID) if !ok { - return nil, http.StatusNotFound, errors.New("delivery service '" + *ds.XMLID + "' not found"), nil + return nil, http.StatusNotFound, errors.New("delivery service '" + ds.XMLID + "' not found"), nil } if err != nil { return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type during update: " + err.Error()) @@ -1020,20 +1005,17 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if userErr != nil || sysErr != nil { return nil, errCode, userErr, sysErr } - if sslKeysExist, err = getSSLVersion(*ds.XMLID, tx); err != nil { + if sslKeysExist, err = getSSLVersion(ds.XMLID, tx); err != nil { return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %s", err) } - if ds.CDNID == nil { - return nil, http.StatusBadRequest, errors.New("invalid request: 'cdnId' cannot be blank"), nil - } if sslKeysExist { - if oldDetails.OldCdnId != *ds.CDNID { + if oldDetails.OldCdnId != ds.CDNID { cdnRoutingDetailDiff = true } if ds.CDNName != nil && oldDetails.OldCdnName != *ds.CDNName { cdnRoutingDetailDiff = true } - if ds.RoutingName != nil && oldDetails.OldRoutingName != *ds.RoutingName { + if oldDetails.OldRoutingName != ds.RoutingName { cdnRoutingDetailDiff = true } if cdnRoutingDetailDiff { @@ -1044,10 +1026,7 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * } // TODO change DeepCachingType to implement sql.Valuer and sql.Scanner, so sqlx struct scan can be used. - deepCachingType := tc.DeepCachingType("").String() - if ds.DeepCachingType != nil { - deepCachingType = ds.DeepCachingType.String() // necessary, because DeepCachingType's default needs to insert the string, not "", and Query doesn't call .String(). - } + 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 { @@ -1210,31 +1189,18 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if !resultRows.Next() { return nil, http.StatusNotFound, errors.New("no delivery service found with this id"), nil } - lastUpdated := tc.TimeNoMod{} + var lastUpdated time.Time if err := resultRows.Scan(&lastUpdated); err != nil { return nil, http.StatusInternalServerError, nil, errors.New("scan updating delivery service: " + err.Error()) } if resultRows.Next() { - xmlID := "" - if ds.XMLID != nil { - xmlID = *ds.XMLID - } - return nil, http.StatusInternalServerError, nil, errors.New("updating delivery service " + xmlID + ": " + "this update affected too many rows: > 1") + 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 ds.XMLID == nil { - return nil, http.StatusInternalServerError, nil, errors.New("missing xml_id after update") - } - if ds.TypeID == nil { - return nil, http.StatusInternalServerError, nil, errors.New("missing type after update") - } - if ds.RoutingName == nil { - return nil, http.StatusInternalServerError, nil, errors.New("missing routing name after update") - } - newDSType, err := getTypeFromID(*ds.TypeID, tx) + newDSType, err := getTypeFromID(ds.TypeID, tx) if err != nil { return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type after update: " + err.Error()) } @@ -1245,17 +1211,17 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * return nil, http.StatusInternalServerError, nil, errors.New("getting CDN domain: (" + cdnDomain + ") after update: " + err.Error()) } - matchLists, err := GetDeliveryServicesMatchLists([]string{*ds.XMLID}, tx) + matchLists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx) if err != nil { return nil, http.StatusInternalServerError, nil, errors.New("getting matchlists after update: " + err.Error()) } - if ml, ok := matchLists[*ds.XMLID]; !ok { + if ml, ok := matchLists[ds.XMLID]; !ok { return nil, http.StatusInternalServerError, nil, errors.New("no matchlists after update") } else { - ds.MatchList = &ml + ds.MatchList = ml } - if err := EnsureParams(tx, *ds.ID, *ds.XMLID, ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.SigningAlgorithm, newDSType, ds.MaxOriginConnections); err != nil { + 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, errors.New("ensuring ds parameters:: " + err.Error()) } @@ -1265,14 +1231,14 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * } } - ds.LastUpdated = &lastUpdated + 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: %s", *ds.XMLID, err.Error()) + 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) + 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 { @@ -1280,7 +1246,7 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * return nil, code, usrErr, sysErr } - if err := api.CreateChangeLogRawErr(api.ApiChange, "Updated ds: "+*ds.XMLID+" id: "+strconv.Itoa(*ds.ID), user, tx); err != nil { + if err := api.CreateChangeLogRawErr(api.ApiChange, "Updated ds: "+ds.XMLID+" id: "+strconv.Itoa(*ds.ID), user, tx); err != nil { return nil, http.StatusInternalServerError, nil, errors.New("writing change log entry: " + err.Error()) } dsV40 = (*tc.DeliveryServiceV40)(&ds) @@ -1299,7 +1265,7 @@ func (ds *TODeliveryService) Delete() (error, error, int) { } else if !ok { return errors.New("delivery service not found"), nil, http.StatusNotFound } - ds.XMLID = &xmlID + ds.XMLID = xmlID // Note ds regexes MUST be deleted before the ds, because there's a ON DELETE CASCADE on deliveryservice_regex (but not on regex). // Likewise, it MUST happen in a transaction with the later DS delete, so they aren't deleted if the DS delete fails. @@ -1319,7 +1285,7 @@ func (ds *TODeliveryService) Delete() (error, error, int) { paramConfigFilePrefixes := []string{"hdr_rw_", "hdr_rw_mid_", "regex_remap_", "cacheurl_"} configFiles := []string{} for _, prefix := range paramConfigFilePrefixes { - configFiles = append(configFiles, prefix+*ds.XMLID+".config") + configFiles = append(configFiles, prefix+ds.XMLID+".config") } if _, err := ds.ReqInfo.Tx.Tx.Exec(`DELETE FROM parameter WHERE name = 'location' AND config_file = ANY($1)`, pq.Array(configFiles)); err != nil { @@ -1533,7 +1499,7 @@ func validateTypeFields(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { latitudeErr := "Must be a floating point number within the range +-90" longitudeErr := "Must be a floating point number within the range +-180" - typeName, err := tc.ValidateTypeID(tx, ds.TypeID, "deliveryservice") + typeName, err := tc.ValidateTypeID(tx, &ds.TypeID, "deliveryservice") if err != nil { return err } @@ -1660,7 +1626,7 @@ func updatePrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi count := 0 q := `SELECT count(*) FROM origin WHERE deliveryservice = $1 AND is_primary` if err := tx.QueryRow(q, *ds.ID).Scan(&count); err != nil { - return fmt.Errorf("querying existing primary origin for ds %s: %s", *ds.XMLID, err.Error()) + return fmt.Errorf("querying existing primary origin for ds %s: %w", ds.XMLID, err) } if ds.OrgServerFQDN == nil || *ds.OrgServerFQDN == "" { @@ -1668,9 +1634,9 @@ func updatePrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi // the update is removing the existing orgServerFQDN, so the existing row needs to be deleted q = `DELETE FROM origin WHERE deliveryservice = $1 AND is_primary` if _, err := tx.Exec(q, *ds.ID); err != nil { - return fmt.Errorf("deleting primary origin for ds %s: %s", *ds.XMLID, err.Error()) + return fmt.Errorf("deleting primary origin for ds %s: %w", ds.XMLID, err) } - api.CreateChangeLogRawTx(api.ApiChange, "DS: "+*ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Deleted primary origin", user, tx) + api.CreateChangeLogRawTx(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Deleted primary origin", user, tx) } return nil } @@ -1688,10 +1654,10 @@ func updatePrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi name := "" q = `UPDATE origin SET protocol = $1, fqdn = $2, port = $3 WHERE is_primary AND deliveryservice = $4 RETURNING name` if err := tx.QueryRow(q, protocol, fqdn, port, *ds.ID).Scan(&name); err != nil { - return fmt.Errorf("update primary origin for ds %s from '%s': %s", *ds.XMLID, *ds.OrgServerFQDN, err.Error()) + return fmt.Errorf("update primary origin for ds %s from '%s': %w", ds.XMLID, *ds.OrgServerFQDN, err) } - api.CreateChangeLogRawTx(api.ApiChange, "DS: "+*ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Updated primary origin: "+name, user, tx) + api.CreateChangeLogRawTx(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Updated primary origin: "+name, user, tx) return nil } @@ -1712,7 +1678,7 @@ func createPrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi return fmt.Errorf("insert origin from '%s': %s", *ds.OrgServerFQDN, err.Error()) } - api.CreateChangeLogRawTx(api.ApiChange, "DS: "+*ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Created primary origin id: "+strconv.Itoa(originID), user, tx) + api.CreateChangeLogRawTx(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Created primary origin id: "+strconv.Itoa(originID), user, tx) return nil } @@ -1831,10 +1797,9 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s } } - dsCDNDomains[*ds.XMLID] = cdnDomain - if ds.DeepCachingType != nil { - *ds.DeepCachingType = tc.DeepCachingTypeFromString(string(*ds.DeepCachingType)) - } + dsCDNDomains[ds.XMLID] = cdnDomain + ds.DeepCachingType = tc.DeepCachingTypeFromString(string(ds.DeepCachingType)) + ds.Signed = ds.SigningAlgorithm != nil && *ds.SigningAlgorithm == tc.SigningAlgorithmURLSig dses = append(dses, ds) @@ -1842,7 +1807,7 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s dsNames := make([]string, len(dses), len(dses)) for i, ds := range dses { - dsNames[i] = *ds.XMLID + dsNames[i] = ds.XMLID } matchLists, err := GetDeliveryServicesMatchLists(dsNames, tx.Tx) @@ -1850,12 +1815,12 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s return nil, nil, errors.New("getting delivery service matchlists: " + err.Error()), http.StatusInternalServerError } for i, ds := range dses { - matchList, ok := matchLists[*ds.XMLID] + matchList, ok := matchLists[ds.XMLID] if !ok { continue } - ds.MatchList = &matchList - ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *ds.Type, *ds.RoutingName, *ds.MatchList, dsCDNDomains[*ds.XMLID]) + ds.MatchList = matchList + ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *ds.Type, ds.RoutingName, ds.MatchList, dsCDNDomains[ds.XMLID]) dses[i] = ds } @@ -2121,14 +2086,14 @@ func deleteLocationParam(tx *sql.Tx, configFile string) error { // getTenantID returns the tenant Id of the given delivery service. Note it may return a nil id and nil error, if the tenant ID in the database is nil. func getTenantID(tx *sql.Tx, ds *tc.DeliveryServiceV4) (*int, error) { - if ds.ID == nil && ds.XMLID == nil { - return nil, errors.New("delivery service has no ID or XMLID") + if ds == nil || ds.ID == nil { + return nil, errors.New("delivery service was nil or has no ID") } if ds.ID != nil { existingID, _, err := getDSTenantIDByID(tx, *ds.ID) // ignore exists return - if the DS is new, we only need to check the user input tenant return existingID, err } - existingID, _, err := getDSTenantIDByName(tx, tc.DeliveryServiceName(*ds.XMLID)) // ignore exists return - if the DS is new, we only need to check the user input tenant + existingID, _, err := getDSTenantIDByName(tx, tc.DeliveryServiceName(ds.XMLID)) // ignore exists return - if the DS is new, we only need to check the user input tenant return existingID, err } @@ -2140,10 +2105,7 @@ func isTenantAuthorized(inf *api.APIInfo, ds *tc.DeliveryServiceV4) (bool, error if err != nil { return false, errors.New("getting tenant ID: " + err.Error()) } - if ds.TenantID == nil { - ds.TenantID = existingID - } - if existingID != nil && existingID != ds.TenantID { + if existingID != nil { userAuthorizedForExistingDSTenant, err := tenant.IsResourceAuthorizedToUserTx(*existingID, user, tx) if err != nil { return false, errors.New("checking authorization for existing DS ID: " + err.Error()) @@ -2152,8 +2114,8 @@ func isTenantAuthorized(inf *api.APIInfo, ds *tc.DeliveryServiceV4) (bool, error return false, nil } } - if ds.TenantID != nil { - userAuthorizedForNewDSTenant, err := tenant.IsResourceAuthorizedToUserTx(*ds.TenantID, user, tx) + if ds.TenantID != 0 { + userAuthorizedForNewDSTenant, err := tenant.IsResourceAuthorizedToUserTx(ds.TenantID, user, tx) if err != nil { return false, errors.New("checking authorization for new DS ID: " + err.Error()) } @@ -2230,11 +2192,8 @@ func sanitize(ds *tc.DeliveryServiceV4) { &ds.InnerHeaderRewrite, &ds.LastHeaderRewrite, ) - if ds.RoutingName == nil || *ds.RoutingName == "" { - ds.RoutingName = util.StrPtr(tc.DefaultRoutingName) - } - if ds.AnonymousBlockingEnabled == nil { - ds.AnonymousBlockingEnabled = util.BoolPtr(false) + if ds.RoutingName == "" { + ds.RoutingName = tc.DefaultRoutingName } signedAlgorithm := tc.SigningAlgorithmURLSig if ds.Signed && (ds.SigningAlgorithm == nil || *ds.SigningAlgorithm == "") { @@ -2246,11 +2205,7 @@ func sanitize(ds *tc.DeliveryServiceV4) { if ds.MaxOriginConnections == nil || *ds.MaxOriginConnections < 0 { ds.MaxOriginConnections = util.IntPtr(0) } - if ds.DeepCachingType == nil { - s := tc.DeepCachingType("") - ds.DeepCachingType = &s - } - *ds.DeepCachingType = tc.DeepCachingTypeFromString(string(*ds.DeepCachingType)) + ds.DeepCachingType = tc.DeepCachingTypeFromString(string(ds.DeepCachingType)) if ds.MaxRequestHeaderBytes == nil { ds.MaxRequestHeaderBytes = util.IntPtr(tc.DefaultMaxRequestHeaderBytes) } diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go index 09e65f09d0..aeb2f2753d 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go @@ -309,11 +309,7 @@ func Get(w http.ResponseWriter, r *http.Request) { // DeliveryService's Tenant, as appropriate to the change type. func isTenantAuthorized(dsr tc.DeliveryServiceRequestV40, inf *api.APIInfo) (bool, error) { if dsr.Requested != nil && (dsr.ChangeType == tc.DSRChangeTypeUpdate || dsr.ChangeType == tc.DSRChangeTypeCreate) { - if dsr.Requested.TenantID == nil { - log.Debugf("requested.tenantID is nil") - return false, errors.New("requested.tenantID is nil") - } - ok, err := tenant.IsResourceAuthorizedToUserTx(*dsr.Requested.TenantID, inf.User, inf.Tx.Tx) + ok, err := tenant.IsResourceAuthorizedToUserTx(dsr.Requested.TenantID, inf.User, inf.Tx.Tx) if err != nil { err = fmt.Errorf("requested: %v", err) } @@ -328,11 +324,7 @@ func isTenantAuthorized(dsr tc.DeliveryServiceRequestV40, inf *api.APIInfo) (boo return true, nil } - if ds.TenantID == nil { - log.Debugf("original.tenantID is nil") - return false, errors.New("original.tenantID is nil") - } - ok, err := tenant.IsResourceAuthorizedToUserTx(*ds.TenantID, inf.User, inf.Tx.Tx) + ok, err := tenant.IsResourceAuthorizedToUserTx(ds.TenantID, inf.User, inf.Tx.Tx) if err != nil { err = fmt.Errorf("original: %v", err) } diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go index 49e47ea805..359693faf5 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go @@ -121,7 +121,7 @@ func validateV4(dsr tc.DeliveryServiceRequestV40, tx *sql.Tx) (error, error) { } err := deliveryservice.Validate(tx, ds) if err == nil { - dsr.XMLID = *ds.XMLID + dsr.XMLID = ds.XMLID } return err }, diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/safe.go b/traffic_ops/traffic_ops_golang/deliveryservice/safe.go index bd9a8911c6..94cb0b763a 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/safe.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/safe.go @@ -138,7 +138,7 @@ func UpdateSafe(w http.ResponseWriter, r *http.Request) { api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV30{ds.DowngradeToV3()}) } - api.CreateChangeLogRawTx(api.ApiChange, fmt.Sprintf("DS: %s, ID: %d, ACTION: Updated safe fields", *ds.XMLID, *ds.ID), inf.User, tx) + api.CreateChangeLogRawTx(api.ApiChange, fmt.Sprintf("DS: %s, ID: %d, ACTION: Updated safe fields", ds.XMLID, *ds.ID), inf.User, tx) } // updateDSSafe updates the given delivery service in the database. Returns whether the DS existed, and any error. diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go b/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go index aba4fef756..16c5fe89da 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go @@ -131,27 +131,14 @@ func delete(w http.ResponseWriter, r *http.Request, deprecated bool) { } ds := dses[0] - if ds.Active == nil { - errCode = http.StatusInternalServerError - sysErr = fmt.Errorf("Delivery Service #%d had nil Active", dsID) - api.HandleErrOptionalDeprecation(w, r, tx, errCode, nil, sysErr, deprecated, &alt) - return - } - - if *ds.Active { + if ds.Active { errCode, userErr, sysErr = checkLastServer(dsID, serverID, tx) if userErr != nil || sysErr != nil { api.HandleErrOptionalDeprecation(w, r, inf.Tx.Tx, errCode, userErr, sysErr, deprecated, &alt) return } } - if ds.XMLID == nil { - errCode = http.StatusInternalServerError - sysErr = fmt.Errorf("Delivery Service #%d had nil XMLID", dsID) - api.HandleErrOptionalDeprecation(w, r, tx, errCode, nil, sysErr, deprecated, &alt) - return - } - dsName := *ds.XMLID + dsName := ds.XMLID serverName, exists, err := dbhelpers.GetServerNameFromID(tx, serverID) if err != nil { diff --git a/traffic_ops/v4-client/deliveryservice.go b/traffic_ops/v4-client/deliveryservice.go index a77bc1b523..d4af55655d 100644 --- a/traffic_ops/v4-client/deliveryservice.go +++ b/traffic_ops/v4-client/deliveryservice.go @@ -75,7 +75,7 @@ const ( // apiDeliveryServiceGenerateSSLKeys is the API path on which Traffic Ops will generate new SSL keys. apiDeliveryServiceGenerateSSLKeys = apiDeliveryServices + "/sslkeys/generate" - // apiDeliveryServiceAddSSLKeys is the API path on which Traffic Ops will add SSL keys + // apiDeliveryServiceAddSSLKeys is the API path on which Traffic Ops will add SSL keys. apiDeliveryServiceAddSSLKeys = apiDeliveryServices + "/sslkeys/add" // apiDeliveryServiceURISigningKeys is the API path on which Traffic Ops serves information @@ -134,7 +134,7 @@ func (to *Session) GetDeliveryServices(opts RequestOptions) (tc.DeliveryServices func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOptions) (tc.DeliveryServicesResponseV4, toclientlib.ReqInf, error) { var reqInf toclientlib.ReqInf var resp tc.DeliveryServicesResponseV4 - if ds.TypeID == nil && ds.Type != nil { + if ds.TypeID <= 0 && ds.Type != nil { typeOpts := NewRequestOptions() typeOpts.QueryParameters.Set("name", ds.Type.String()) ty, _, err := to.GetTypes(typeOpts) @@ -144,10 +144,10 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp if len(ty.Response) == 0 { return resp, reqInf, fmt.Errorf("no Type named '%s'", ds.Type) } - ds.TypeID = &ty.Response[0].ID + ds.TypeID = ty.Response[0].ID } - if ds.CDNID == nil && ds.CDNName != nil { + if ds.CDNID <= 0 && ds.CDNName != nil { cdnOpts := NewRequestOptions() cdnOpts.QueryParameters.Set("name", *ds.CDNName) cdns, _, err := to.GetCDNs(cdnOpts) @@ -158,7 +158,7 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp if len(cdns.Response) == 0 { return resp, reqInf, fmt.Errorf("no CDN named '%s'", *ds.CDNName) } - ds.CDNID = &cdns.Response[0].ID + ds.CDNID = cdns.Response[0].ID } if ds.ProfileID == nil && ds.ProfileName != nil { @@ -174,7 +174,7 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp ds.ProfileID = &profiles.Response[0].ID } - if ds.TenantID == nil && ds.Tenant != nil { + if ds.TenantID <= 0 && ds.Tenant != nil { tenantOpts := NewRequestOptions() tenantOpts.QueryParameters.Set("name", *ds.Tenant) ten, _, err := to.GetTenants(tenantOpts) @@ -184,7 +184,7 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp if len(ten.Response) == 0 { return resp, reqInf, fmt.Errorf("no Tenant named '%s'", *ds.Tenant) } - ds.TenantID = &ten.Response[0].ID + ds.TenantID = ten.Response[0].ID } reqInf, err := to.post(apiDeliveryServices, RequestOptions{Header: opts.Header}, ds, &resp) @@ -257,7 +257,7 @@ func (to *Session) GenerateSSLKeysForDS( return response, reqInf, err } -// AddSSLKeysForDS adds SSL Keys for the given DS +// AddSSLKeysForDS adds SSL Keys for the given Delivery Service. func (to *Session) AddSSLKeysForDS(request tc.DeliveryServiceAddSSLKeysReq, opts RequestOptions) (tc.SSLKeysAddResponse, toclientlib.ReqInf, error) { var response tc.SSLKeysAddResponse reqInf, err := to.post(apiDeliveryServiceAddSSLKeys, opts, request, &response) @@ -322,7 +322,7 @@ func (to *Session) GetDeliveryServiceURISigningKeys(dsName string, opts RequestO } // CreateDeliveryServiceURISigningKeys creates new URI-signing keys used by the Delivery Service -// identified by the XMLID 'dsXMLID' +// identified by the XMLID 'dsXMLID'. func (to *Session) CreateDeliveryServiceURISigningKeys(dsXMLID string, body map[string]tc.URISignerKeyset, opts RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) { var alerts tc.Alerts reqInf, err := to.post(fmt.Sprintf(apiDeliveryServicesURISigningKeys, url.PathEscape(dsXMLID)), opts, body, &alerts) @@ -330,7 +330,7 @@ func (to *Session) CreateDeliveryServiceURISigningKeys(dsXMLID string, body map[ } // DeleteDeliveryServiceURISigningKeys deletes the URI-signing keys used by the Delivery Service -// identified by the XMLID 'dsXMLID' +// identified by the XMLID 'dsXMLID'. func (to *Session) DeleteDeliveryServiceURISigningKeys(dsXMLID string, opts RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) { var alerts tc.Alerts reqInf, err := to.del(fmt.Sprintf(apiDeliveryServicesURISigningKeys, url.PathEscape(dsXMLID)), opts, &alerts) diff --git a/traffic_ops/v4-client/deliveryservice_requests.go b/traffic_ops/v4-client/deliveryservice_requests.go index 89e59575d0..ae2ee6f357 100644 --- a/traffic_ops/v4-client/deliveryservice_requests.go +++ b/traffic_ops/v4-client/deliveryservice_requests.go @@ -65,24 +65,24 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequestV4, ds = dsr.Requested } - if ds.TypeID == nil && ds.Type.String() != "" { + if ds.TypeID <= 0 && ds.Type.String() != "" { typeOpts := NewRequestOptions() typeOpts.QueryParameters.Set("name", ds.Type.String()) ty, reqInf, err := to.GetTypes(typeOpts) if err != nil || len(ty.Response) == 0 { return resp, reqInf, errors.New("no type named " + ds.Type.String()) } - ds.TypeID = &ty.Response[0].ID + ds.TypeID = ty.Response[0].ID } - if ds.CDNID == nil && ds.CDNName != nil { + if ds.CDNID <= 0 && ds.CDNName != nil { cdnOpts := NewRequestOptions() cdnOpts.QueryParameters.Set("name", *ds.CDNName) cdns, reqInf, err := to.GetCDNs(cdnOpts) if err != nil || len(cdns.Response) == 0 { return resp, reqInf, fmt.Errorf("no CDN named '%s'", *ds.CDNName) } - ds.CDNID = &cdns.Response[0].ID + ds.CDNID = cdns.Response[0].ID } if ds.ProfileID == nil && ds.ProfileName != nil { @@ -95,14 +95,14 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequestV4, ds.ProfileID = &profiles.Response[0].ID } - if ds.TenantID == nil && ds.Tenant != nil { + if ds.TenantID <= 0 && ds.Tenant != nil { tenantOpts := NewRequestOptions() tenantOpts.QueryParameters.Set("name", *ds.Tenant) ten, reqInf, err := to.GetTenants(tenantOpts) if err != nil || len(ten.Response) == 0 { return resp, reqInf, fmt.Errorf("no Tenant named '%s'", *ds.Tenant) } - ds.TenantID = &ten.Response[0].ID + ds.TenantID = ten.Response[0].ID } reqInf, err := to.post(apiDSRequests, opts, dsr, &resp) From 963a5647739f921f333777079d6975e147ef4769 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 26 May 2021 10:57:19 -0600 Subject: [PATCH 03/34] Add TLSVersions handling and validation for invalid versions to /deliveryservices --- .../deliveryservice/deliveryservices.go | 105 +++++++++++++++++- 1 file changed, 100 insertions(+), 5 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index ea8e20cfb1..23aeea2ffe 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -325,6 +325,50 @@ func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 t return &oldRes, status, userErr, sysErr } +// 'ON CONFLICT DO NOTHING' should be unnecessary because all data should be +// dumped from the table before re-insertion, but it's also harmless because +// the only conflict that could occur is a fully duplicate row, which is fine +// since we're intending to create that data anyway. Although it is weird. +const insertTLSVersionsQuery = ` +INSERT INTO public.deliveryservice_tls_version (deliveryservice, tls_version) + SELECT + $1 AS deliveryservice + UNNEST($2) AS tls_version +ON CONFLICT DO NOTHING +` + +func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { + err := tx.QueryRow(`DELETE FROM public.deliveryservice_tls_version WHERE deliveryservice = $1`, dsid).Scan() + if err != nil { + return fmt.Errorf("cleaning up existing TLS version for DS #%d: %w", dsid, err) + } + + if len(versions) < 1 { + return nil + } + + rows, err := tx.Query(insertTLSVersionsQuery, dsid, pq.Array(versions)) + if err != nil { + return fmt.Errorf("inserting new TLS versions: %w", err) + } + defer func() { + err = rows.Close() + if err != nil { + log.Errorln("closing TLS versions insert rows: %v", err) + } + }() + + rowsAffected := 0 + for rows.Next() { + rowsAffected++ + } + if rowsAffected != len(versions) { + return fmt.Errorf("inserting %d TLS versions for DS #%d affected %d rows", len(versions), dsid, rowsAffected) + } + + return nil +} + // create creates the given ds in the database, and returns the DS with its id and other fields created on insert set. On error, the HTTP status code, user error, and system error are returned. The status code SHOULD NOT be used, if both errors are nil. func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, int, error, error) { var resultRows *sql.Rows @@ -503,6 +547,15 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t } ds.Type = &dsType + // Don't touch TLSVersions if using old API versions + if inf.Version != nil && inf.Version.Major >= 4 { + 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, errors.New("creating default regex: " + err.Error()) } @@ -1200,6 +1253,17 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if ds.ID == nil { return nil, http.StatusInternalServerError, nil, errors.New("missing id after update") } + + if inf.Version != nil && inf.Version.Major >= 4 { + 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, errors.New("getting delivery service type after update: " + err.Error()) @@ -1416,6 +1480,8 @@ func requiredIfMatchesTypeName(patterns []string, typeName string) func(interfac } } +var validTLSVersionPattern = regexp.MustCompile(`^\d+\.\d+$`) + func Validate(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { sanitize(ds) neverOrAlways := validation.NewStringRule(tovalidate.IsOneOfStringICase("NEVER", "ALWAYS"), @@ -1436,8 +1502,27 @@ func Validate(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { "regionalGeoBlocking": validation.Validate(ds.RegionalGeoBlocking, validation.NotNil), "remapText": validation.Validate(ds.RemapText, noLineBreaks), "routingName": validation.Validate(ds.RoutingName, isDNSName, noPeriods, validation.Length(1, 48)), - "typeId": validation.Validate(ds.TypeID, validation.Required, validation.Min(1)), - "xmlId": validation.Validate(ds.XMLID, validation.Required, noSpaces, noPeriods, validation.Length(1, 48)), + "tlsVersions": validation.Validate(ds.TLSVersions, validation.By( + func(value interface{}) error { + vers, ok := value.([]string) + if !ok { + return fmt.Errorf("must be an array of string, got: %T", value) + } + seen := make(map[string]struct{}, len(vers)) + for _, tlsVersion := range vers { + if _, ok := seen[tlsVersion]; ok { + return fmt.Errorf("duplicate version '%s'", tlsVersion) + } + seen[tlsVersion] = struct{}{} + if !validTLSVersionPattern.Match([]byte(tlsVersion)) { + return fmt.Errorf("invalid TLS version '%s'", tlsVersion) + } + } + return nil + }, + )), + "typeId": validation.Validate(ds.TypeID, validation.Required, validation.Min(1)), + "xmlId": validation.Validate(ds.XMLID, validation.Required, noSpaces, noPeriods, validation.Length(1, 48)), }) if err := validateTopologyFields(ds); err != nil { errs = append(errs, err) @@ -1516,7 +1601,7 @@ func validateTypeFields(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { "initialDispersion": validation.Validate(ds.InitialDispersion, validation.By(requiredIfMatchesTypeName([]string{HTTPRegexType}, typeName)), validation.By(tovalidate.IsGreaterThanZero)), - "ipv6RoutingEnabled": validation.Validate(ds.IPV6RoutingEnabled, + "ipv6RoutingEnabled": validation.Validate(&ds.IPV6RoutingEnabled, validation.By(requiredIfMatchesTypeName([]string{SteeringRegexType, DNSRegexType, HTTPRegexType}, typeName))), "missLat": validation.Validate(ds.MissLat, validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName)), @@ -1772,6 +1857,7 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s &ds.SSLKeyVersion, &ds.TenantID, &ds.Tenant, + pq.Array(&ds.TLSVersions), &ds.Topology, &ds.TRRequestHeaders, &ds.TRResponseHeaders, @@ -1802,6 +1888,10 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s ds.Signed = ds.SigningAlgorithm != nil && *ds.SigningAlgorithm == tc.SigningAlgorithmURLSig + if len(ds.TLSVersions) < 1 { + ds.TLSVersions = nil + } + dses = append(dses, ds) } @@ -2086,8 +2176,8 @@ func deleteLocationParam(tx *sql.Tx, configFile string) error { // getTenantID returns the tenant Id of the given delivery service. Note it may return a nil id and nil error, if the tenant ID in the database is nil. func getTenantID(tx *sql.Tx, ds *tc.DeliveryServiceV4) (*int, error) { - if ds == nil || ds.ID == nil { - return nil, errors.New("delivery service was nil or has no ID") + if ds == nil { + return nil, errors.New("delivery service was nil") } if ds.ID != nil { existingID, _, err := getDSTenantIDByID(tx, *ds.ID) // ignore exists return - if the DS is new, we only need to check the user input tenant @@ -2282,6 +2372,11 @@ ds.active, ds.ssl_key_version, ds.tenant_id, tenant.name, + ( + SELECT ARRAY_AGG(tls_version ORDER BY tls_version) + FROM deliveryservice_tls_version + WHERE deliveryservice = ds.id + ) AS tls_versions, ds.topology, ds.tr_request_headers, ds.tr_response_headers, From 1c65065005e7625026c3ec7984200efea6bb766b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 26 May 2021 12:32:58 -0600 Subject: [PATCH 04/34] Fix incorrect responses from /deliveryservices/{ID}/safe Previously, it would return APIv3.1 structures for API version 1.5, 2.0, 3.0, 3.1, and 4.0 (as well as unrecognized versions). It now returns the appropriate version structures for each requested version. This fixes #5891 --- .../deliveryservice/safe.go | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/safe.go b/traffic_ops/traffic_ops_golang/deliveryservice/safe.go index 94cb0b763a..b050198ba5 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/safe.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/safe.go @@ -125,17 +125,39 @@ func UpdateSafe(w http.ResponseWriter, r *http.Request) { ds = ds.RemoveLD1AndLD2() } alertMsg := "Delivery Service safe update successful." - if inf.Version != nil && inf.Version.Major == 1 && inf.Version.Minor < 5 { - switch inf.Version.Minor { + if inf.Version == nil { + log.Warnln("API version found to be null in DS safe update") + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, dses) + } else { + switch inf.Version.Major { + // treat unknown versions as latest + default: + fallthrough case 4: - api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV14{ds.DowngradeToV3().DeliveryServiceNullableV14}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, dses) case 3: - api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV13{ds.DowngradeToV3().DeliveryServiceNullableV13}) - default: - api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV12{ds.DowngradeToV3().DeliveryServiceNullableV12}) + if inf.Version.Minor >= 1 { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceV31{tc.DeliveryServiceV31(ds.DowngradeToV3())}) + } + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceV30{ds.DowngradeToV3().DeliveryServiceV30}) + case 2: + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV15{ds.DowngradeToV3().DeliveryServiceNullableV15}) + case 1: + switch inf.Version.Minor { + default: + fallthrough + case 5: + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV15{ds.DowngradeToV3().DeliveryServiceNullableV15}) + case 4: + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV14{ds.DowngradeToV3().DeliveryServiceNullableV14}) + case 3: + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV13{ds.DowngradeToV3().DeliveryServiceNullableV13}) + case 2: + fallthrough + case 1: + api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV12{ds.DowngradeToV3().DeliveryServiceNullableV12}) + } } - } else { - api.WriteRespAlertObj(w, r, tc.SuccessLevel, alertMsg, []tc.DeliveryServiceNullableV30{ds.DowngradeToV3()}) } api.CreateChangeLogRawTx(api.ApiChange, fmt.Sprintf("DS: %s, ID: %d, ACTION: Updated safe fields", ds.XMLID, *ds.ID), inf.User, tx) From 2d3b9b0f98a82bab5bcbc864b6f16d04628c99eb Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 26 May 2021 14:50:45 -0600 Subject: [PATCH 05/34] Fix DSRs storing/returning APIv4 DSes with empty tlsVersions instead of null --- .../deliveryservice/request/requests.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go index aeb2f2753d..e01de60c59 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go @@ -455,12 +455,18 @@ func createV4(w http.ResponseWriter, r *http.Request, inf *api.APIInfo) (result api.HandleErr(w, r, tx, http.StatusBadRequest, errors.New("the longDesc1 and longDesc2 fields are no longer supported in API 4.0 onwards"), nil) return } + if len(dsr.Original.TLSVersions) < 1 { + dsr.Original.TLSVersions = nil + } } if dsr.Requested != nil { if dsr.Requested.LongDesc1 != nil || dsr.Requested.LongDesc2 != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, errors.New("the longDesc1 and longDesc2 fields are no longer supported in API 4.0 onwards"), nil) return } + if len(dsr.Requested.TLSVersions) < 1 { + dsr.Requested.TLSVersions = nil + } } errCode, userErr, sysErr := insert(&dsr, inf) if userErr != nil || sysErr != nil { @@ -723,6 +729,13 @@ func putV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo) (result ds dsr.LastEditedByID = new(int) *dsr.LastEditedByID = inf.User.ID + if dsr.Requested != nil && len(dsr.Requested.TLSVersions) < 1 { + dsr.Requested.TLSVersions = nil + } + if dsr.Original != nil && len(dsr.Original.TLSVersions) < 1 { + dsr.Original.TLSVersions = nil + } + args := []interface{}{ dsr.AssigneeID, dsr.ChangeType, From 614cb32f0f55b02e9ae27d1e913992513fd82393 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 27 May 2021 10:31:03 -0600 Subject: [PATCH 06/34] Fix being unable to update DSes with no TLS versions --- .../traffic_ops_golang/deliveryservice/deliveryservices.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 23aeea2ffe..28354db37f 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -339,7 +339,7 @@ ON CONFLICT DO NOTHING func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { err := tx.QueryRow(`DELETE FROM public.deliveryservice_tls_version WHERE deliveryservice = $1`, dsid).Scan() - if err != nil { + if err != nil && !errors.Is(err, sql.ErrNoRows) { return fmt.Errorf("cleaning up existing TLS version for DS #%d: %w", dsid, err) } From cbf726e48c2fc5dd1df13986c83ca1545f714555 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 09:23:55 -0600 Subject: [PATCH 07/34] Add ATC "known" TLS versions and a warning generation function for possibly insecure version sets --- lib/go-tc/deliveryservices.go | 121 +++++++++++++++++++++++ lib/go-tc/deliveryservices_test.go | 152 ++++++++++++++++++++++++++++- 2 files changed, 272 insertions(+), 1 deletion(-) diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go index c54fa05a40..387704e795 100644 --- a/lib/go-tc/deliveryservices.go +++ b/lib/go-tc/deliveryservices.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "strings" "time" "github.com/apache/trafficcontrol/lib/go-util" @@ -483,6 +484,126 @@ type DeliveryServiceV40 struct { // Traffic Ops API - it always points to the highest minor version in APIv4. type DeliveryServiceV4 = DeliveryServiceV40 +// These are the TLS Versions known by Apache Traffic Control to exist. +const ( + // Deprecated: TLS version 1.0 is known to be insecure. + TLSVersion10 = "1.0" + // Deprecated: TLS version 1.1 is known to be insecure. + TLSVersion11 = "1.1" + TLSVersion12 = "1.2" + TLSVersion13 = "1.3" +) + +func newerDisallowedMessage(old string, newer []string) string { + l := len(newer) + if l < 1 { + return "" + } + + var msg strings.Builder + msg.WriteString("old TLS version ") + msg.WriteString(old) + msg.WriteString(" is allowed, but newer version") + if l > 1 { + msg.WriteRune('s') + } + msg.WriteRune(' ') + msg.WriteString(newer[0]) + if l > 1 { + msg.WriteString(", ") + if l > 2 { + msg.WriteString(newer[1]) + msg.WriteString(", and ") + msg.WriteString(newer[2]) + } else { + msg.WriteString("and ") + msg.WriteString(newer[1]) + } + msg.WriteString(" are ") + } else { + msg.WriteString(" is ") + } + msg.WriteString("disallowed; this configuration may be insecure") + + return msg.String() +} + +// TLSVersionsAlerts generates warning-level alerts for the given TLS versions +// array. It will warn if newer versions are disallowed while older, less +// secure versions are allowed, or if there are unrecognized versions present. +// +// This does NOT verify that the passed TLS versions are _valid_, it ONLY +// creates warnings based on conditions that are possibly detrimental to CDN +// operation, but can, in fact, work. +func TLSVersionsAlerts(vers []string) Alerts { + if len(vers) < 1 { + return Alerts{Alerts: []Alert{}} + } + messages := []string{} + + found := map[string]bool{ + TLSVersion10: false, + TLSVersion11: false, + TLSVersion12: false, + TLSVersion13: false, + } + + for _, v := range vers { + switch v { + case TLSVersion10: + found[TLSVersion10] = true + case TLSVersion11: + found[TLSVersion11] = true + case TLSVersion12: + found[TLSVersion12] = true + case TLSVersion13: + found[TLSVersion13] = true + default: + messages = append(messages, "unknown TLS version '"+v+"' - possible typo") + } + } + + if found[TLSVersion10] { + var newerDisallowed []string + if !found[TLSVersion11] { + newerDisallowed = append(newerDisallowed, TLSVersion11) + } + if !found[TLSVersion12] { + newerDisallowed = append(newerDisallowed, TLSVersion12) + } + if !found[TLSVersion13] { + newerDisallowed = append(newerDisallowed, TLSVersion13) + } + msg := newerDisallowedMessage(TLSVersion10, newerDisallowed) + if msg != "" { + messages = append(messages, msg) + } + } else if found[TLSVersion11] { + var newerDisallowed []string + if !found[TLSVersion12] { + newerDisallowed = append(newerDisallowed, TLSVersion12) + } + if !found[TLSVersion13] { + newerDisallowed = append(newerDisallowed, TLSVersion13) + } + msg := newerDisallowedMessage(TLSVersion11, newerDisallowed) + if msg != "" { + messages = append(messages, msg) + } + } else if found[TLSVersion12] { + var newerDisallowed []string + if !found[TLSVersion13] { + newerDisallowed = append(newerDisallowed, TLSVersion13) + } + msg := newerDisallowedMessage(TLSVersion12, newerDisallowed) + if msg != "" { + messages = append(messages, msg) + } + } + + return CreateAlerts(WarnLevel, messages...) +} + type DeliveryServiceV30 struct { DeliveryServiceNullableV15 DeliveryServiceFieldsV30 diff --git a/lib/go-tc/deliveryservices_test.go b/lib/go-tc/deliveryservices_test.go index c4f2791215..49ffe4e370 100644 --- a/lib/go-tc/deliveryservices_test.go +++ b/lib/go-tc/deliveryservices_test.go @@ -14,7 +14,10 @@ package tc * limitations under the License. */ -import "testing" +import ( + "fmt" + "testing" +) func compareV31DSes(a, b DeliveryServiceNullableV30, t *testing.T) { if (a.Active == nil && b.Active != nil) || (a.Active != nil && b.Active == nil) { @@ -675,3 +678,150 @@ func TestDeliveryServiceUpgradeAndDowngrade(t *testing.T) { t.Errorf("Expected 'tlsVersions' to be nil after upgrade, because all TLS versions are implicitly supported for an APIv3 DS; found: %v", upgraded.TLSVersions) } } + +func expectOnlyWarnings(a Alerts) func(*testing.T) { + return func(t *testing.T) { + found := 0 + for _, alert := range a.Alerts { + if alert.Level != WarnLevel.String() { + found++ + } + } + + if found > 0 { + t.Errorf("Expected only warning-level alerts, found %d that were not warning-level: %v", found, a.Alerts) + } + } +} + +func containsWarning(a Alerts, expected string) func(*testing.T) { + return func(t *testing.T) { + for _, alert := range a.Alerts { + if alert.Level == WarnLevel.String() && alert.Text == expected { + return + } + } + t.Errorf("Expected to find a warning-level Alert containing the message '%s', but didn't: %v", expected, a.Alerts) + } +} + +func TestTLSVersionsAlerts(t *testing.T) { + var vers []string + alerts := TLSVersionsAlerts(vers) + if alerts.HasAlerts() { + t.Errorf("nil versions should not produce any warnings, but these were generated: %v", alerts.Alerts) + } + vers = make([]string, 0, 3) + alerts = TLSVersionsAlerts(vers) + if alerts.HasAlerts() { + t.Errorf("empty versions should not produce any warnings, but these were generated: %v", alerts.Alerts) + } + + expected := "old TLS version 1.0 is allowed, but newer versions 1.1, 1.2, and 1.3 are disallowed; this configuration may be insecure" + vers = append(vers, TLSVersion10) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 1 { + t.Errorf("expected allowing only TLS v1.0 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + } else { + t.Run("only TLS version 1.0 allowed - returns warnings", expectOnlyWarnings(alerts)) + t.Run("only TLS version 1.0 allowed - has expected warning", containsWarning(alerts, expected)) + } + + expected = "old TLS version 1.0 is allowed, but newer versions 1.1, and 1.3 are disallowed; this configuration may be insecure" + vers = append(vers, TLSVersion12) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 1 { + t.Errorf("expected allowing only TLS v1.0 and 1.2 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + } else { + t.Run("only TLS versions 1.0 and 1.2 allowed - returns warnings", expectOnlyWarnings(alerts)) + t.Run("only TLS versions 1.0 and 1.2 allowed - has expected warning", containsWarning(alerts, expected)) + } + + expected = "old TLS version 1.0 is allowed, but newer version 1.3 is disallowed; this configuration may be insecure" + vers = append(vers, TLSVersion11) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 1 { + t.Errorf("expected disallowing only TLS v1.3 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + } else { + t.Run("only TLS version 1.3 disallowed - returns warnings", expectOnlyWarnings(alerts)) + t.Run("only TLS version 1.3 disallowed - has expected warning", containsWarning(alerts, expected)) + } + + expected = "old TLS version 1.1 is allowed, but newer versions 1.2, and 1.3 are disallowed; this configuration may be insecure" + vers = make([]string, 0, 2) + vers = append(vers, TLSVersion11) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 1 { + t.Errorf("expected allowing only TLS v1.1 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + } else { + t.Run("only TLS version 1.1 allowed - returns warnings", expectOnlyWarnings(alerts)) + t.Run("only TLS version 1.1 allowed - has expected warning", containsWarning(alerts, expected)) + } + + expected = "old TLS version 1.1 is allowed, but newer version 1.3 is disallowed; this configuration may be insecure" + vers = append(vers, TLSVersion12) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 1 { + t.Errorf("expected allowing only TLS v1.1 and 1.2 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + } else { + t.Run("only TLS versions 1.1 and 1.2 allowed - returns warnings", expectOnlyWarnings(alerts)) + t.Run("only TLS versions 1.1 and 1.2 allowed - has expected warning", containsWarning(alerts, expected)) + } + + expected = "old TLS version 1.2 is allowed, but newer version 1.3 is disallowed; this configuration may be insecure" + vers = make([]string, 0, 4) + vers = append(vers, TLSVersion12) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 1 { + t.Errorf("expected allowing only TLS v1.2 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + } else { + t.Run("only TLS version 1.2 allowed - returns warnings", expectOnlyWarnings(alerts)) + t.Run("only TLS version 1.2 allowed - has expected warning", containsWarning(alerts, expected)) + } + + vers = append(vers, TLSVersion13) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) > 0 { + t.Errorf("Expected allowing TLS versions 1.2 and 1.3 to not generate any warnings, got %d: %v", len(alerts.Alerts), alerts.Alerts) + } + + expected = "unknown TLS version '13.37' - possible typo" + vers = append(vers, "13.37") + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 1 { + t.Errorf("expected allowing an unknown TLS version to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts.Alerts) + } else { + t.Run("unknown TLS version allowed - returns warnings", expectOnlyWarnings(alerts)) + t.Run("unknown TLS version allowed - has expected warning", containsWarning(alerts, expected)) + } + + vers = append(vers, TLSVersion10) + alerts = TLSVersionsAlerts(vers) + if len(alerts.Alerts) != 2 { + t.Errorf("expected allowing an unknown TLS version and disallowing only version 1.1 to generate exactly two warnings, got %d: %v", len(alerts.Alerts), alerts.Alerts) + } else { + t.Run("unknown TLS version and disallowed v1.1 - returns warnings", expectOnlyWarnings(alerts)) + t.Run("unknown TLS version and disallowed v1.1 - has expected warning", containsWarning(alerts, expected)) + expected = "old TLS version 1.0 is allowed, but newer version 1.1 is disallowed; this configuration may be insecure" + t.Run("unknown TLS version and disallowed v1.1 - has second expected warning", containsWarning(alerts, expected)) + } +} + +func BenchmarkTLSVersionsAlerts(b *testing.B) { + versions := make([]string, 0, 101) + for major := 1; major <= 10; major++ { + for minor := 0; minor < 10; minor++ { + if major == 1 && minor == 1 { + // skip this one to force generating some more warnings + continue + } + versions = append(versions, fmt.Sprintf("%d.%d", major, minor)) + } + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + TLSVersionsAlerts(versions) + } +} From 5c15609bf2aefd9347e1b727c41874b26ce95b03 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 09:27:48 -0600 Subject: [PATCH 08/34] Add tlsVersions warnings to /deliveryservices --- .../deliveryservice/deliveryservices.go | 402 +++++++++++------- 1 file changed, 249 insertions(+), 153 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 28354db37f..405ad0ab0d 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -121,12 +121,17 @@ func CreateV12(w http.ResponseWriter, r *http.Request) { return } - res, status, userErr, sysErr := createV12(w, r, inf, ds) + res, alerts, status, userErr, sysErr := createV12(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation was successful.", []tc.DeliveryServiceNullableV12{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV12{*res}) } func CreateV13(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -142,12 +147,17 @@ func CreateV13(w http.ResponseWriter, r *http.Request) { return } - res, status, userErr, sysErr := createV13(w, r, inf, ds) + res, alerts, status, userErr, sysErr := createV13(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation was successful.", []tc.DeliveryServiceNullableV13{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV13{*res}) } func CreateV14(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -163,12 +173,17 @@ func CreateV14(w http.ResponseWriter, r *http.Request) { return } - res, status, userErr, sysErr := createV14(w, r, inf, ds) + res, alerts, status, userErr, sysErr := createV14(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation was successful.", []tc.DeliveryServiceNullableV14{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV14{*res}) } // TODO allow users to post names (type, cdn, etc) and get the IDs from the names. This isn't trivial to do in a single query, without dynamically building the entire insert query, and ideally inserting would be one query. But it'd be much more convenient for users. Alternatively, remove IDs from the database entirely and use real candidate keys. @@ -186,12 +201,17 @@ func CreateV15(w http.ResponseWriter, r *http.Request) { return } - res, status, userErr, sysErr := createV15(w, r, inf, ds) + res, alerts, status, userErr, sysErr := createV15(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation was successful.", []tc.DeliveryServiceNullableV15{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV15{*res}) } func CreateV30(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -207,12 +227,17 @@ func CreateV30(w http.ResponseWriter, r *http.Request) { return } - res, status, userErr, sysErr := createV30(w, r, inf, ds) + res, alerts, status, userErr, sysErr := createV30(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation was successful.", []tc.DeliveryServiceV30{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV30{*res}) } func CreateV31(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -228,12 +253,17 @@ func CreateV31(w http.ResponseWriter, r *http.Request) { return } - res, status, userErr, sysErr := createV31(w, r, inf, ds) + res, alerts, status, userErr, sysErr := createV31(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation was successful.", []tc.DeliveryServiceV31{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV31{*res}) } func CreateV40(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -249,61 +279,67 @@ func CreateV40(w http.ResponseWriter, r *http.Request) { return } - res, status, userErr, sysErr := createV40(w, r, inf, ds, true) + res, alerts, status, userErr, sysErr := createV40(w, r, inf, ds, true) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation was successful.", []tc.DeliveryServiceV40{*res}) + if res == nil || res.ID == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil or had nil ID")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") + w.Header().Set("Location", fmt.Sprintf("/api/4.0/deliveryservices?id=%d", *res.ID)) + api.WriteAlertsObj(w, r, http.StatusCreated, alerts, []tc.DeliveryServiceV40{*res}) } -func createV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, int, error, error) { +func createV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, tc.Alerts, int, error, error) { dsV13 := tc.DeliveryServiceNullableV13{DeliveryServiceNullableV12: reqDS} - res, status, userErr, sysErr := createV13(w, r, inf, dsV13) + res, alerts, status, userErr, sysErr := createV13(w, r, inf, dsV13) if res != nil { - return &res.DeliveryServiceNullableV12, status, userErr, sysErr + return &res.DeliveryServiceNullableV12, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func createV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, int, error, error) { +func createV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, tc.Alerts, int, error, error) { dsV14 := tc.DeliveryServiceNullableV14{DeliveryServiceNullableV13: reqDS} - res, status, userErr, sysErr := createV14(w, r, inf, dsV14) + res, alerts, status, userErr, sysErr := createV14(w, r, inf, dsV14) if res != nil { - return &res.DeliveryServiceNullableV13, status, userErr, sysErr + return &res.DeliveryServiceNullableV13, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func createV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, int, error, error) { +func createV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, tc.Alerts, int, error, error) { dsV15 := tc.DeliveryServiceNullableV15{DeliveryServiceNullableV14: reqDS} - res, status, userErr, sysErr := createV15(w, r, inf, dsV15) + res, alerts, status, userErr, sysErr := createV15(w, r, inf, dsV15) if res != nil { - return &res.DeliveryServiceNullableV14, status, userErr, sysErr + return &res.DeliveryServiceNullableV14, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func createV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, int, error, error) { +func createV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, tc.Alerts, int, error, error) { dsV30 := tc.DeliveryServiceV30{DeliveryServiceNullableV15: reqDS} - res, status, userErr, sysErr := createV30(w, r, inf, dsV30) + res, alerts, status, userErr, sysErr := createV30(w, r, inf, dsV30) if res != nil { - return &res.DeliveryServiceNullableV15, status, userErr, sysErr + return &res.DeliveryServiceNullableV15, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func createV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, int, error, error) { +func createV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, tc.Alerts, int, error, error) { ds := tc.DeliveryServiceV31{DeliveryServiceV30: dsV30} - res, status, userErr, sysErr := createV31(w, r, inf, ds) + res, alerts, status, userErr, sysErr := createV31(w, r, inf, ds) if res != nil { - return &res.DeliveryServiceV30, status, userErr, sysErr + return &res.DeliveryServiceV30, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, int, error, error) { +func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, tc.Alerts, int, error, error) { tx := inf.Tx.Tx dsNullable := tc.DeliveryServiceNullableV30(dsV31) ds := dsNullable.UpgradeToV4() - res, status, userErr, sysErr := createV40(w, r, inf, tc.DeliveryServiceV40(ds), false) + res, alerts, status, userErr, sysErr := createV40(w, r, inf, tc.DeliveryServiceV40(ds), false) if res == nil { - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } ds = tc.DeliveryServiceV4(*res) @@ -313,16 +349,16 @@ func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 t &ds.ID) if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, code, usrErr, sysErr + return nil, alerts, code, usrErr, sysErr } } if err := EnsureCacheURLParams(tx, *ds.ID, ds.XMLID, dsV31.CacheURL); err != nil { - return nil, http.StatusInternalServerError, nil, err + return nil, alerts, http.StatusInternalServerError, nil, err } oldRes := tc.DeliveryServiceV31(ds.DowngradeToV3()) - return &oldRes, status, userErr, sysErr + return &oldRes, alerts, status, userErr, sysErr } // 'ON CONFLICT DO NOTHING' should be unnecessary because all data should be @@ -369,32 +405,52 @@ func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { return nil } +// generates warning-level alerts (if any are necessary) for a Delivery Service +// based on its TLS Versions. This will panic if handed a nil transaction. +func generateTLSVersionWarnings(ds tc.DeliveryServiceV4, tx *sql.Tx) tc.Alerts { + alerts := tc.TLSVersionsAlerts(ds.TLSVersions) + + var httpType int + if err := tx.QueryRow(`SELECT id FROM public.type WHERE name = 'HTTP'`).Scan(&httpType); err != nil { + log.Errorln("Failed to get 'HTTP' type: ", err.Error()) + } else if httpType == ds.TypeID { + if len(ds.TLSVersions) >= 1 { + alerts.AddNewAlert(tc.WarnLevel, "tlsVersions has no effect on 'HTTP' Delivery Services") + } + } else if len(ds.TLSVersions) >= 1 { + alerts.AddNewAlert(tc.WarnLevel, "setting TLS Versions that are explicitly supported may break older clients that can't use the specified versions") + } + + return alerts +} + // create creates the given ds in the database, and returns the DS with its id and other fields created on insert set. On error, the HTTP status code, user error, and system error are returned. The status code SHOULD NOT be used, if both errors are nil. -func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, int, error, error) { - var resultRows *sql.Rows - var err error +func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, tc.Alerts, int, error, error) { user := inf.User tx := inf.Tx.Tx ds := tc.DeliveryServiceV4(dsV40) - if err := Validate(tx, &ds); err != nil { - return nil, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil + var alerts tc.Alerts + err := Validate(tx, &ds) + if err != nil { + return nil, alerts, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil } if authorized, err := isTenantAuthorized(inf, &ds); err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) } else if !authorized { - return nil, http.StatusForbidden, errors.New("not authorized on this tenant"), nil + return nil, alerts, 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 := 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 + return nil, alerts, errCode, userErr, sysErr } + var resultRows *sql.Rows if omitExtraLongDescFields { if ds.LongDesc1 != nil || ds.LongDesc2 != nil { - return nil, http.StatusBadRequest, errors.New("the longDesc1 and longDesc2 fields are no longer supported in API 4.0 onwards"), nil + return nil, alerts, 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, @@ -521,29 +577,29 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, code, usrErr, sysErr + return nil, alerts, code, usrErr, sysErr } defer resultRows.Close() id := 0 var lastUpdated time.Time if !resultRows.Next() { - return nil, http.StatusInternalServerError, nil, errors.New("no deliveryservice request inserted, no id was returned") + return nil, alerts, http.StatusInternalServerError, nil, errors.New("no deliveryservice request inserted, no id was returned") } if err := resultRows.Scan(&id, &lastUpdated); err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("could not scan id from insert: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("could not scan id from insert: " + err.Error()) } if resultRows.Next() { - return nil, http.StatusInternalServerError, nil, errors.New("too many ids returned from deliveryservice request insert") + return nil, alerts, 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") + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing id after insert") } dsType, err := getTypeFromID(ds.TypeID, tx) if err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type: " + err.Error()) } ds.Type = &dsType @@ -552,60 +608,62 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t 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) + return nil, alerts, 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, errors.New("creating default regex: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating default regex: " + err.Error()) } if _, err := createConsistentHashQueryParams(tx, *ds.ID, ds.ConsistentHashQueryParams); err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, code, usrErr, sysErr + return nil, alerts, code, usrErr, sysErr } matchlists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx) if err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: " + err.Error()) } if matchlist, ok := matchlists[ds.XMLID]; !ok { - return nil, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: not found") + return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: not found") } else { ds.MatchList = matchlist } cdnName, cdnDomain, dnssecEnabled, err := getCDNNameDomainDNSSecEnabled(*ds.ID, tx) if err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("creating DS: getting CDN info: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: getting CDN info: " + err.Error()) } ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *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, errors.New("ensuring ds parameters:: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) } if dnssecEnabled && 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") + return nil, alerts, 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 + return nil, alerts, statusCode, userErr, sysErr } } if err := createPrimaryOrigin(tx, user, ds); err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("creating delivery service: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating delivery service: " + err.Error()) } 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, errors.New("error writing to audit log: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("error writing to audit log: " + err.Error()) } + alerts = generateTLSVersionWarnings(ds, tx) + dsV40 = tc.DeliveryServiceV40(ds) - return &dsV40, http.StatusOK, nil, nil + return &dsV40, alerts, http.StatusOK, nil, nil } func createDefaultRegex(tx *sql.Tx, dsID int, xmlID string) error { @@ -695,12 +753,17 @@ func UpdateV12(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, status, userErr, sysErr := updateV12(w, r, inf, &ds) + res, alerts, status, userErr, sysErr := updateV12(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update was successful.", []tc.DeliveryServiceNullableV12{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV12{*res}) } func UpdateV13(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -719,12 +782,17 @@ func UpdateV13(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, status, userErr, sysErr := updateV13(w, r, inf, &ds) + res, alerts, status, userErr, sysErr := updateV13(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update was successful.", []tc.DeliveryServiceNullableV13{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV13{*res}) } func UpdateV14(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -743,12 +811,17 @@ func UpdateV14(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, status, userErr, sysErr := updateV14(w, r, inf, &ds) + res, alerts, status, userErr, sysErr := updateV14(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update was successful.", []tc.DeliveryServiceNullableV14{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV14{*res}) } func UpdateV15(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -767,12 +840,17 @@ func UpdateV15(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, status, userErr, sysErr := updateV15(w, r, inf, &ds) + res, alerts, status, userErr, sysErr := updateV15(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update was successful.", []tc.DeliveryServiceNullableV15{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV15{*res}) } func UpdateV30(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -791,12 +869,17 @@ func UpdateV30(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, status, userErr, sysErr := updateV30(w, r, inf, &ds) + res, alerts, status, userErr, sysErr := updateV30(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update was successful.", []tc.DeliveryServiceV30{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV30{*res}) } func UpdateV31(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -814,12 +897,17 @@ func UpdateV31(w http.ResponseWriter, r *http.Request) { return } ds.ID = &id - res, status, userErr, sysErr := updateV31(w, r, inf, &ds) + res, alerts, status, userErr, sysErr := updateV31(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update was successful.", []tc.DeliveryServiceV31{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV31{*res}) } func UpdateV40(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -837,15 +925,20 @@ func UpdateV40(w http.ResponseWriter, r *http.Request) { return } ds.ID = &id - res, status, userErr, sysErr := updateV40(w, r, inf, &ds, true) + res, alerts, status, userErr, sysErr := updateV40(w, r, inf, &ds, true) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update was successful.", []tc.DeliveryServiceV40{*res}) + if res == nil { + api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) + return + } + alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") + api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV40{*res}) } -func updateV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, int, error, error) { +func updateV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, tc.Alerts, int, error, error) { dsV13 := tc.DeliveryServiceNullableV13{DeliveryServiceNullableV12: *reqDS} // query the DB for existing 1.3 fields in order to "upgrade" this 1.2 request into a 1.3 request query := ` @@ -867,21 +960,21 @@ WHERE &dsV13.TRRequestHeaders, ); err != nil { if err == sql.ErrNoRows { - return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV13.ID), nil + return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV13.ID), nil } - return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV13.ID, err.Error()) + return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV13.ID, err.Error()) } if dsV13.DeepCachingType != nil { *dsV13.DeepCachingType = tc.DeepCachingTypeFromString(string(*dsV13.DeepCachingType)) } - res, status, userErr, sysErr := updateV13(w, r, inf, &dsV13) + res, alerts, status, userErr, sysErr := updateV13(w, r, inf, &dsV13) if res != nil { - return &res.DeliveryServiceNullableV12, status, userErr, sysErr + return &res.DeliveryServiceNullableV12, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func updateV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, int, error, error) { +func updateV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, tc.Alerts, int, error, error) { dsV14 := tc.DeliveryServiceNullableV14{DeliveryServiceNullableV13: *reqDS} // query the DB for existing 1.4 fields in order to "upgrade" this 1.3 request into a 1.4 request query := ` @@ -901,17 +994,17 @@ WHERE pq.Array(&dsV14.ConsistentHashQueryParams), ); err != nil { if err == sql.ErrNoRows { - return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV14.ID), nil + return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV14.ID), nil } - return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV14.ID, err.Error()) + return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV14.ID, err.Error()) } - res, status, userErr, sysErr := updateV14(w, r, inf, &dsV14) + res, alerts, status, userErr, sysErr := updateV14(w, r, inf, &dsV14) if res != nil { - return &res.DeliveryServiceNullableV13, status, userErr, sysErr + return &res.DeliveryServiceNullableV13, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func updateV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, int, error, error) { +func updateV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, tc.Alerts, int, error, error) { dsV15 := tc.DeliveryServiceNullableV15{DeliveryServiceNullableV14: *reqDS} // query the DB for existing 1.5 fields in order to "upgrade" this 1.4 request into a 1.5 request query := ` @@ -927,17 +1020,17 @@ WHERE &dsV15.RangeSliceBlockSize, ); err != nil { if err == sql.ErrNoRows { - return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV15.ID), nil + return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV15.ID), nil } - return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV15.ID, err.Error()) + return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV15.ID, err.Error()) } - res, status, userErr, sysErr := updateV15(w, r, inf, &dsV15) + res, alerts, status, userErr, sysErr := updateV15(w, r, inf, &dsV15) if res != nil { - return &res.DeliveryServiceNullableV14, status, userErr, sysErr + return &res.DeliveryServiceNullableV14, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func updateV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, int, error, error) { +func updateV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, tc.Alerts, int, error, error) { dsV30 := tc.DeliveryServiceV30{DeliveryServiceNullableV15: *reqDS} // query the DB for existing 3.0 fields in order to "upgrade" this 1.5 request into a 3.0 request query := ` @@ -959,17 +1052,17 @@ WHERE &dsV30.ServiceCategory, ); err != nil { if err == sql.ErrNoRows { - return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV30.ID), nil + return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV30.ID), nil } - return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV30.ID, err.Error()) + return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV30.ID, err.Error()) } - res, status, userErr, sysErr := updateV30(w, r, inf, &dsV30) + res, alerts, status, userErr, sysErr := updateV30(w, r, inf, &dsV30) if res != nil { - return &res.DeliveryServiceNullableV15, status, userErr, sysErr + return &res.DeliveryServiceNullableV15, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func updateV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 *tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, int, error, error) { +func updateV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 *tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, tc.Alerts, int, error, error) { dsV31 := tc.DeliveryServiceV31{DeliveryServiceV30: *dsV30} // query the DB for existing 3.1 fields in order to "upgrade" this 3.0 request into a 3.1 request query := ` @@ -983,69 +1076,68 @@ WHERE &dsV31.MaxRequestHeaderBytes, ); err != nil { if err == sql.ErrNoRows { - return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV31.ID), nil + return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV31.ID), nil } - return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV31.ID, err.Error()) + return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV31.ID, err.Error()) } - res, status, userErr, sysErr := updateV31(w, r, inf, &dsV31) + res, alerts, status, userErr, sysErr := updateV31(w, r, inf, &dsV31) if res != nil { - return &res.DeliveryServiceV30, status, userErr, sysErr + return &res.DeliveryServiceV30, alerts, status, userErr, sysErr } - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } -func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 *tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, int, error, error) { +func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 *tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, tc.Alerts, int, error, error) { dsNull := tc.DeliveryServiceNullableV30(*dsV31) ds := dsNull.UpgradeToV4() - dsV40 := tc.DeliveryServiceV40(ds) + dsV40 := ds tx := inf.Tx.Tx - res, status, usrErr, sysErr := updateV40(w, r, inf, &dsV40, false) + res, alerts, status, usrErr, sysErr := updateV40(w, r, inf, &dsV40, false) if res == nil { - return nil, status, usrErr, sysErr + return nil, alerts, status, usrErr, sysErr } - ds = tc.DeliveryServiceV4(*res) + ds = *res if dsV31.CacheURL != nil { _, err := tx.Exec("UPDATE deliveryservice SET cacheurl = $1 WHERE ID = $2", &dsV31.CacheURL, &ds.ID) if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, code, usrErr, sysErr + return nil, alerts, code, usrErr, sysErr } } if err := EnsureCacheURLParams(tx, *ds.ID, ds.XMLID, dsV31.CacheURL); err != nil { - return nil, http.StatusInternalServerError, nil, err + return nil, alerts, http.StatusInternalServerError, nil, err } oldRes := tc.DeliveryServiceV31(ds.DowngradeToV3()) - return &oldRes, http.StatusOK, nil, nil + return &oldRes, alerts, http.StatusOK, nil, nil } -func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 *tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, int, error, error) { - var resultRows *sql.Rows - var err error +func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 *tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, tc.Alerts, int, error, error) { tx := inf.Tx.Tx user := inf.User + var alerts tc.Alerts ds := tc.DeliveryServiceV4(*dsV40) if err := Validate(tx, &ds); err != nil { - return nil, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil + return nil, alerts, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil } if authorized, err := isTenantAuthorized(inf, &ds); err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) } else if !authorized { - return nil, http.StatusForbidden, errors.New("not authorized on this tenant"), nil + return nil, alerts, http.StatusForbidden, errors.New("not authorized on this tenant"), nil } if ds.ID == nil { - return nil, http.StatusBadRequest, errors.New("missing id"), nil + return nil, alerts, 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 + return nil, alerts, http.StatusNotFound, errors.New("delivery service '" + ds.XMLID + "' not found"), nil } if err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type during update: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type during update: " + err.Error()) } errCode := http.StatusOK @@ -1056,10 +1148,10 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if dsType.HasSSLKeys() { oldDetails, userErr, sysErr, errCode = getOldDetails(*ds.ID, tx) if userErr != nil || sysErr != nil { - return nil, errCode, userErr, sysErr + return nil, alerts, errCode, userErr, sysErr } if sslKeysExist, err = getSSLVersion(ds.XMLID, tx); err != nil { - return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %s", err) + return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %s", err) } if sslKeysExist { if oldDetails.OldCdnId != ds.CDNID { @@ -1072,7 +1164,7 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * cdnRoutingDetailDiff = true } if cdnRoutingDetailDiff { - return nil, http.StatusBadRequest, errors.New("delivery service has ssl keys that cannot be automatically changed, therefore CDN and routing name are immutable"), nil + return nil, alerts, http.StatusBadRequest, errors.New("delivery service has ssl keys that cannot be automatically changed, therefore CDN and routing name are immutable"), nil } ds.SSLKeyVersion = oldDetails.OldSSLKeyVersion } @@ -1083,33 +1175,34 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * userErr, sysErr, errCode = api.CheckIfUnModified(r.Header, inf.Tx, *ds.ID, "deliveryservice") if userErr != nil || sysErr != nil { - return nil, errCode, userErr, sysErr + return nil, alerts, errCode, userErr, sysErr } if errCode, userErr, sysErr = dbhelpers.CheckTopology(inf.Tx, ds); userErr != nil || sysErr != nil { - return nil, errCode, userErr, sysErr + return nil, alerts, errCode, userErr, sysErr } if ds.Topology != nil { requiredCapabilities, err := dbhelpers.GetDSRequiredCapabilitiesFromID(*ds.ID, tx) if err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("getting existing DS required capabilities: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting existing DS required capabilities: " + err.Error()) } if len(requiredCapabilities) > 0 { if userErr, sysErr, status := EnsureTopologyBasedRequiredCapabilities(tx, *ds.ID, *ds.Topology, requiredCapabilities); userErr != nil || sysErr != nil { - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } } userErr, sysErr, status := dbhelpers.CheckOriginServerInDSCG(tx, *ds.ID, *ds.Topology) if userErr != nil || sysErr != nil { - return nil, status, userErr, sysErr + return nil, alerts, status, userErr, sysErr } } + var resultRows *sql.Rows if omitExtraLongDescFields { if ds.LongDesc1 != nil || ds.LongDesc2 != nil { - return nil, http.StatusBadRequest, errors.New("the longDesc1 and longDesc2 fields are no longer supported in API 4.0 onwards"), nil + return nil, alerts, 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, @@ -1236,22 +1329,22 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, code, usrErr, sysErr + return nil, alerts, code, usrErr, sysErr } defer resultRows.Close() if !resultRows.Next() { - return nil, http.StatusNotFound, errors.New("no delivery service found with this id"), nil + return nil, alerts, 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, errors.New("scan updating delivery service: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("scan updating delivery service: " + err.Error()) } if resultRows.Next() { - return nil, http.StatusInternalServerError, nil, errors.New("updating delivery service " + ds.XMLID + ": " + "this update affected too many rows: > 1") + return nil, alerts, 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") + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing id after update") } if inf.Version != nil && inf.Version.Major >= 4 { @@ -1260,38 +1353,38 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * } 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) + return nil, alerts, 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, errors.New("getting delivery service type after update: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type after update: " + err.Error()) } ds.Type = &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, errors.New("getting CDN domain: (" + cdnDomain + ") after update: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting CDN domain: (" + cdnDomain + ") after update: " + err.Error()) } matchLists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx) if err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("getting matchlists after update: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting matchlists after update: " + err.Error()) } if ml, ok := matchLists[ds.XMLID]; !ok { - return nil, http.StatusInternalServerError, nil, errors.New("no matchlists after update") + return nil, alerts, http.StatusInternalServerError, nil, errors.New("no matchlists after update") } else { 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, errors.New("ensuring ds parameters:: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) } if oldDetails.OldOrgServerFqdn != nil && ds.OrgServerFQDN != nil && *oldDetails.OldOrgServerFqdn != *ds.OrgServerFQDN { if err := updatePrimaryOrigin(tx, user, ds); err != nil { - return nil, http.StatusInternalServerError, nil, errors.New("updating delivery service: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("updating delivery service: " + err.Error()) } } @@ -1300,21 +1393,24 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * // 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) + return nil, alerts, 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 + return nil, alerts, 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, errors.New("writing change log entry: " + err.Error()) + return nil, alerts, http.StatusInternalServerError, nil, errors.New("writing change log entry: " + err.Error()) } + + alerts = generateTLSVersionWarnings(ds, tx) + dsV40 = (*tc.DeliveryServiceV40)(&ds) - return dsV40, http.StatusOK, nil, nil + return dsV40, alerts, http.StatusOK, nil, nil } //Delete is the DeliveryService implementation of the Deleter interface. From a728a1edb7fbd7af03b3bff4bd5491677438d3cb Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 09:28:20 -0600 Subject: [PATCH 09/34] Add validation that prevents tlsVersions on STEERING/CLIENT_STEERING delivery services --- .../deliveryservice/deliveryservices.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 405ad0ab0d..84f3b43920 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -1735,6 +1735,18 @@ func validateTypeFields(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName))), "rangeRequestHandling": validation.Validate(ds.RangeRequestHandling, validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName))), + "tlsVersions": validation.Validate( + &ds.TLSVersions, + validation.By( + func(value interface{}) error { + vers := value.(*[]string) + if vers != nil && len(*vers) > 0 && tc.DSType(typeName).IsSteering() { + return errors.New("must be 'null' for STEERING-Type and CLIENT_STEERING-Type Delivery Services") + } + return nil + }, + ), + ), "topology": validation.Validate(ds, validation.By(func(dsi interface{}) error { ds := dsi.(*tc.DeliveryServiceV4) From 9631e9f8b0425c9b15ea871e5bdf5e1feb334ff8 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 09:28:44 -0600 Subject: [PATCH 10/34] Fix a bug where adding TLS versions returns a 500 ISE response --- .../deliveryservice/deliveryservices.go | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 84f3b43920..f219629c94 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -368,8 +368,8 @@ func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 t const insertTLSVersionsQuery = ` INSERT INTO public.deliveryservice_tls_version (deliveryservice, tls_version) SELECT - $1 AS deliveryservice - UNNEST($2) AS tls_version + $1 AS deliveryservice, + UNNEST($2::text[]) AS tls_version ON CONFLICT DO NOTHING ` @@ -387,19 +387,12 @@ func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { if err != nil { return fmt.Errorf("inserting new TLS versions: %w", err) } - defer func() { - err = rows.Close() - if err != nil { - log.Errorln("closing TLS versions insert rows: %v", err) - } - }() - - rowsAffected := 0 - for rows.Next() { - rowsAffected++ + err = rows.Close() + if err != nil { + log.Errorln("closing TLS versions insert rows: ", err.Error()) } - if rowsAffected != len(versions) { - return fmt.Errorf("inserting %d TLS versions for DS #%d affected %d rows", len(versions), dsid, rowsAffected) + if err = rows.Err(); err != nil { + log.Errorln("an error occurred at some point in the TLS insertion query: ", err.Error()) } return nil From 31c2fef143277dbd35e637dc1f9518df3403b2fd Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 11:41:13 -0600 Subject: [PATCH 11/34] Fix indirection of non-pointer value --- traffic_ops/testing/api/v4/deliveryservices_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/traffic_ops/testing/api/v4/deliveryservices_test.go b/traffic_ops/testing/api/v4/deliveryservices_test.go index f398b1e06e..0e5bf98a0b 100644 --- a/traffic_ops/testing/api/v4/deliveryservices_test.go +++ b/traffic_ops/testing/api/v4/deliveryservices_test.go @@ -2053,9 +2053,9 @@ func DeleteTestDeliveryServicesURISigningKeys(t *testing.T) { t.Errorf("Unexpected error deleting URI Signing keys for Delivery Service '%s': %v - alerts: %+v", firstDS.XMLID, err, resp.Alerts) } - emptyBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) + emptyBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", *firstDS.XMLID, err) + t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", firstDS.XMLID, err) } emptyMap := make(map[string]interface{}) err = json.Unmarshal(emptyBytes, &emptyMap) From 98bd97e8e2305a76af3ba36ebbdfe52ab5c7b076 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 12:31:35 -0600 Subject: [PATCH 12/34] Add TLS versions tests to the v4 API client --- .../testing/api/v4/deliveryservices_test.go | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/traffic_ops/testing/api/v4/deliveryservices_test.go b/traffic_ops/testing/api/v4/deliveryservices_test.go index 0e5bf98a0b..21064b6b9f 100644 --- a/traffic_ops/testing/api/v4/deliveryservices_test.go +++ b/traffic_ops/testing/api/v4/deliveryservices_test.go @@ -90,6 +90,7 @@ func TestDeliveryServices(t *testing.T) { t.Run("GET request using the 'type' query string parameter", GetDeliveryServiceByValidType) t.Run("GET request using the 'xmlId' query string parameter", GetDeliveryServiceByValidXmlId) t.Run("Descending order sorted response to GET request", SortTestDeliveryServicesDesc) + t.Run("TLS Versions property", addTLSVersionsToDeliveryService) }) } @@ -2266,3 +2267,90 @@ func SortTestDeliveryServicesDesc(t *testing.T) { t.Errorf("Delivery Service responses are not equal after reversal: %v - %v", respDesc[0].XMLID, respAsc[0].XMLID) } } + +func addTLSVersionsToDeliveryService(t *testing.T) { + me, _, err := TOSession.GetUserCurrent(client.RequestOptions{}) + if err != nil { + t.Fatalf("Failed to get current User: %v - alerts: %+v", err, me.Alerts) + } + if me.Response.Tenant == nil || me.Response.TenantID == nil { + t.Fatal("Traffic Ops returned a representation for the current user with null or undefined tenant and/or tenantID") + } + + ds := tc.DeliveryServiceV4{ + CDNName: new(string), + DisplayName: "ds-test-tls-versions", + InitialDispersion: new(int), + MissLat: new(float64), + MissLong: new(float64), + MultiSiteOrigin: new(bool), + OrgServerFQDN: new(string), + Protocol: new(int), + QStringIgnore: new(int), + RangeRequestHandling: new(int), + Tenant: new(string), + TenantID: *me.Response.TenantID, + TLSVersions: []string{ + "1.1", + }, + Type: new(tc.DSType), + XMLID: "ds-test-tls-versions", + } + *ds.InitialDispersion = 1 + *ds.Tenant = *me.Response.Tenant + + cdns, _, err := TOSession.GetCDNs(client.RequestOptions{}) + if err != nil { + t.Fatalf("Failed to get CDNs: %v - alerts: %+v", err, cdns.Alerts) + } + if len(cdns.Response) < 1 { + t.Fatalf("Need at least one CDN to exist in order to test Delivery Service TLS Versions") + } + ds.CDNID = cdns.Response[0].ID + *ds.CDNName = cdns.Response[0].Name + + *ds.Type = "STEERING" + opts := client.NewRequestOptions() + opts.QueryParameters.Set("name", string(*ds.Type)) + types, _, err := TOSession.GetTypes(opts) + if err != nil { + t.Fatalf("Failed to get Types: %v - alerts: %+v", err, types.Alerts) + } + if len(types.Response) != 1 { + t.Fatalf("Expected exactly one Type to exist named 'STEERING', found: %d", len(types.Response)) + } + ds.TypeID = types.Response[0].ID + + _, _, err = TOSession.CreateDeliveryService(ds, client.RequestOptions{}) + if err == nil { + t.Error("Expected an error creating a STEERING Delivery Service with explicit TLS Versions, but didn't") + } else if !strings.Contains(err.Error(), "'tlsVersions' must be 'null' for STEERING-Type") { + t.Errorf("Expected an error about non-null TLS Versions for STEERING-Type Delivery Services, got: %v", err) + } + + *ds.Type = "HTTP" + opts.QueryParameters.Set("name", string(*ds.Type)) + types, _, err = TOSession.GetTypes(opts) + if err != nil { + t.Fatalf("Failed to get Types: %v - alerts: %+v", err, types.Alerts) + } + if len(types.Response) != 1 { + t.Fatalf("Expected exactly one Type to exist named 'HTTP', found: %d", len(types.Response)) + } + ds.TypeID = types.Response[0].ID + + *ds.OrgServerFQDN = "https://origin.test" + resp, _, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) + if err != nil { + t.Errorf("Unexpected error creating a Delivery Service: %v - alerts: %+v", err, resp.Alerts) + } else if len(resp.Response) != 1 { + t.Errorf("Expected creating a new Delivery Service to create exactly one Delivery Service, but Traffic Ops indicated that %d were created", len(resp.Response)) + } else if resp.Response[0].ID == nil { + t.Error("Traffic Ops returned a representation for a created Delivery Service that had null or undefined ID") + } else { + alerts, _, err := TOSession.DeleteDeliveryService(*resp.Response[0].ID, client.RequestOptions{}) + if err != nil { + t.Errorf("Failed to clean up newly created Delivery Service: %v - alerts: %+v", err, alerts.Alerts) + } + } +} From 07be77a935a92895c688d55287b875d06bc3e9b9 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 12:40:03 -0600 Subject: [PATCH 13/34] Remove 'lastUpdated' timestamps from testing data This breaks parsing when the API endpoints that use this data change from our custom format to RFC3339. --- traffic_ops/testing/api/v4/tc-fixtures.json | 98 --------------------- 1 file changed, 98 deletions(-) diff --git a/traffic_ops/testing/api/v4/tc-fixtures.json b/traffic_ops/testing/api/v4/tc-fixtures.json index a648a788df..52ac6ec9ed 100644 --- a/traffic_ops/testing/api/v4/tc-fixtures.json +++ b/traffic_ops/testing/api/v4/tc-fixtures.json @@ -442,7 +442,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "d s 1", "longDesc1": "ds1", @@ -509,7 +508,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "d s 1", "longDesc1": "ds2", @@ -577,7 +575,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "d s 3", "longDesc1": "ds3", @@ -641,7 +638,6 @@ "infoUrl": "", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "", "longDesc1": "", @@ -762,7 +758,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "mso DS 1", "longDesc1": "msods1", @@ -829,7 +824,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "d s 1", "longDesc1": "ds1nat", @@ -892,7 +886,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "d s top", "longDesc1": "ds top", @@ -959,7 +952,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "", "longDesc1": "", @@ -1023,7 +1015,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "", "longDesc1": "", @@ -1087,7 +1078,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "d s client-steering", "longDesc1": "ds client-steering", @@ -1150,7 +1140,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "", "longDesc1": "", @@ -1214,7 +1203,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "", "longDesc1": "", @@ -1278,7 +1266,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "", "longDesc1": "", @@ -1342,7 +1329,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "", "longDesc1": "", @@ -1410,7 +1396,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 15:48:51+00", "logsEnabled": false, "longDesc": "d s inactive", "longDesc1": "dsinactive", @@ -1502,7 +1487,6 @@ "infoUrl": "TBD", "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2018-04-06 16:48:51+00", "logsEnabled": false, "longDesc": "d s 4", "longDesc1": "ds4", @@ -1682,119 +1666,102 @@ "parameters": [ { "configFile": "rascal.properties", - "lastUpdated": "2018-01-19T19:01:21.489534+00:00", "name": "history.count", "secure": false, "value": "30" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.434425+00:00", "name": "CONFIG proxy.config.allocator.enable_reclaim", "secure": false, "value": "INT 0" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.435957+00:00", "name": "CONFIG proxy.config.allocator.max_overage", "secure": false, "value": "INT 3" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.437496+00:00", "name": "CONFIG proxy.config.diags.show_location", "secure": false, "value": "INT 0" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.439033+00:00", "name": "CONFIG proxy.config.http.cache.allow_empty_doc", "secure": false, "value": "INT 0" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.440502+00:00", "name": "LOCAL proxy.config.cache.interim.storage", "secure": false, "value": "STRING NULL" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.441933+00:00", "name": "CONFIG proxy.config.http.parent_proxy.file", "secure": false, "value": "STRING parent.config" }, { "configFile": "plugin.config", - "lastUpdated": "2018-01-19T19:01:21.447837+00:00", "name": "astats_over_http.so", "secure": false, "value": "_astats 33.101.99.100,172.39.19.39,172.39.19.49,172.39.19.49,172.39.29.49" }, { "configFile": "logs_xml.config", - "lastUpdated": "2018-01-19T19:01:21.461206+00:00", "name": "LogFormat.Name", "secure": false, "value": "custom_ats_2" }, { "configFile": "logs_xml.config", - "lastUpdated": "2018-01-19T19:01:21.462772+00:00", "name": "LogObject.Format", "secure": false, "value": "custom_ats_2" }, { "configFile": "logs_xml.config", - "lastUpdated": "2018-01-19T19:01:21.464259+00:00", "name": "LogObject.Filename", "secure": false, "value": "custom_ats_2" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.467349+00:00", "name": "CONFIG proxy.config.cache.control.filename", "secure": false, "value": "STRING cache.config" }, { "configFile": "plugin.config", - "lastUpdated": "2018-01-19T19:01:21.469075+00:00", "name": "regex_revalidate.so", "secure": false, "value": "--config regex_revalidate.config" }, { "configFile": "records.config", - "lastUpdated": "2018-01-19T19:01:21.49285+00:00", "name": "CONFIG proxy.config.hostdb.storage_size", "secure": false, "value": "INT 33554432" }, { "configFile": "regex_revalidate.config", - "lastUpdated": "2018-01-19T19:01:21.496195+00:00", "name": "maxRevalDurationDays", "secure": false, "value": "90" }, { "configFile": "package", - "lastUpdated": "2018-01-19T19:01:21.499423+00:00", "name": "trafficserver", "secure": false, "value": "5.3.2-765.f4354b9.el7.centos.x86_64" }, { "configFile": "global", - "lastUpdated": "2020-04-21T05:19:43.853831+00:00", "name": "tm.instance_name", "secure": false, "value": "Traffic Ops API Tests" @@ -1806,7 +1773,6 @@ "city": "Denver", "comments": null, "email": null, - "lastUpdated": "2018-01-19T21:19:32.081465+00:00", "name": "Denver", "phone": "303-111-1111", "poc": null, @@ -1820,7 +1786,6 @@ "city": "Boulder", "comments": null, "email": null, - "lastUpdated": "2018-01-19T21:19:32.086195+00:00", "name": "Boulder", "phone": "303-222-2222", "poc": null, @@ -1834,7 +1799,6 @@ "city": "Atlanta", "comments": null, "email": null, - "lastUpdated": "2018-01-19T21:19:32.089538+00:00", "name": "HotAtlanta", "phone": "404-222-2222", "poc": null, @@ -2220,7 +2184,6 @@ { "cdnName": "cdn1", "description": "edge1 description", - "lastUpdated": "2018-03-02T17:27:11.818418+00:00", "name": "EDGE1", "routing_disabled": false, "type": "ATS_PROFILE", @@ -2248,7 +2211,6 @@ { "cdnName": "cdn2", "description": "edge2 description", - "lastUpdated": "2018-03-02T17:27:11.818418+00:00", "name": "EDGEInCDN2", "routing_disabled": false, "type": "ATS_PROFILE" @@ -2256,7 +2218,6 @@ { "cdnName": "cdn4", "description": "edge2 description", - "lastUpdated": "2018-03-02T17:27:11.818418+00:00", "name": "EDGE2", "routing_disabled": false, "type": "ATS_PROFILE" @@ -2271,7 +2232,6 @@ { "cdnName": "cdn1", "description": "mid description", - "lastUpdated": "2018-03-02T17:27:11.80173+00:00", "name": "MID1", "routing_disabled": false, "type": "ATS_PROFILE" @@ -2279,7 +2239,6 @@ { "cdnName": "cdn2", "description": "mid description", - "lastUpdated": "2018-03-02T17:27:11.80173+00:00", "name": "MID2", "routing_disabled": false, "type": "ATS_PROFILE" @@ -2287,7 +2246,6 @@ { "cdnName": "cdn1", "description": "origin description", - "lastUpdated": "2018-03-02T17:27:11.80173+00:00", "name": "ORIGIN1", "routing_disabled": false, "type": "ORG_PROFILE" @@ -2295,7 +2253,6 @@ { "cdnName": "cdn1", "description": "cdn1 description", - "lastUpdated": "2018-03-02T17:27:11.80452+00:00", "name": "CCR1", "routing_disabled": false, "type": "TR_PROFILE" @@ -2303,7 +2260,6 @@ { "cdnName": "cdn2", "description": "cdn2 description", - "lastUpdated": "2018-03-02T17:27:11.807948+00:00", "name": "CCR2", "routing_disabled": false, "type": "TR_PROFILE" @@ -2311,7 +2267,6 @@ { "cdnName": "cdn1", "description": "rascal description", - "lastUpdated": "2018-03-02T17:27:11.813052+00:00", "name": "RASCAL1", "routing_disabled": false, "type": "TM_PROFILE", @@ -2330,14 +2285,12 @@ }, { "configFile": "rascal-config.txt", - "lastUpdated": "2018-01-19T19:01:21.472279+00:00", "name": "peers.polling.interval", "secure": false, "value": "60" }, { "configFile": "rascal-config.txt", - "lastUpdated": "2018-01-19T19:01:21.472279+00:00", "name": "health.polling.interval", "secure": false, "value": "30" @@ -2347,7 +2300,6 @@ { "cdnName": "cdn1", "description": "mso origin description", - "lastUpdated": "2018-03-02T17:27:11.80173+00:00", "name": "MSO", "routing_disabled": false, "type": "ORG_PROFILE" @@ -2434,7 +2386,6 @@ "routerPort": "9000" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2479,7 +2430,6 @@ "routerPort": "9001" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2529,7 +2479,6 @@ "routerPort": "9002" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2579,7 +2528,6 @@ "routerPort": "9003" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2629,7 +2577,6 @@ "routerPort": "9004" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2679,7 +2626,6 @@ "routerPort": "9005" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2730,7 +2676,6 @@ } ], "ipNetmask": "255.255.255.252", - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2780,7 +2725,6 @@ "routerPort": "9007" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2830,7 +2774,6 @@ "routerPort": "9008" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2880,7 +2823,6 @@ "routerPort": "9009" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2930,7 +2872,6 @@ "routerPort": "9010" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2980,7 +2921,6 @@ "routerPort": "9011" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -3030,7 +2970,6 @@ "routerPort": "9012" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -3129,7 +3068,6 @@ "routerPort": "9014" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -3179,7 +3117,6 @@ "routerPort": "9015" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -4060,7 +3997,6 @@ "routerPort": "9038" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -4606,7 +4542,6 @@ "routerPort": "9000" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -4656,7 +4591,6 @@ "routerPort": "9011" } ], - "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -5115,193 +5049,161 @@ "types": [ { "description": "Host header regular expression", - "lastUpdated": "2018-03-02T19:13:46.788583+00:00", "name": "HOST_REGEXP", "useInTable": "regex" }, { "description": "DNS Content routing, RAM cache, National", - "lastUpdated": "2018-03-02T19:13:46.792319+00:00", "name": "DNS_LIVE_NATNL", "useInTable": "deliveryservice" }, { "description": "Other CDN (CDS-IS, Akamai, etc)", - "lastUpdated": "2018-03-02T19:13:46.793921+00:00", "name": "OTHER_CDN", "useInTable": "server" }, { "description": "Client-Controlled Steering Delivery Service", - "lastUpdated": "2018-03-02T19:13:46.795291+00:00", "name": "CLIENT_STEERING", "useInTable": "deliveryservice" }, { "description": "influxdb type", - "lastUpdated": "2018-03-02T19:13:46.796707+00:00", "name": "INFLUXDB", "useInTable": "server" }, { "description": "riak type", - "lastUpdated": "2018-03-02T19:13:46.798008+00:00", "name": "RIAK", "useInTable": "server" }, { "description": "Origin", - "lastUpdated": "2018-03-02T19:13:46.799404+00:00", "name": "ORG", "useInTable": "server" }, { "description": "HTTP Content routing cache in RAM ", - "lastUpdated": "2018-03-02T19:13:46.800738+00:00", "name": "HTTP_LIVE", "useInTable": "deliveryservice" }, { "description": "Active Directory User", - "lastUpdated": "2018-03-02T19:13:46.802044+00:00", "name": "ACTIVE_DIRECTORY", "useInTable": "tm_user" }, { "description": "federation type resolve4", - "lastUpdated": "2018-03-02T19:13:46.803471+00:00", "name": "RESOLVE4", "useInTable": "federation" }, { "description": "Static DNS A entry", - "lastUpdated": "2018-03-02T19:13:46.804776+00:00", "name": "A_RECORD", "useInTable": "staticdnsentry" }, { "description": "Local User", - "lastUpdated": "2018-03-02T19:13:46.806035+00:00", "name": "LOCAL", "useInTable": "tm_user" }, { "description": "Weighted steering target", - "lastUpdated": "2018-03-02T19:13:46.80748+00:00", "name": "STEERING_WEIGHT", "useInTable": "steering_target" }, { "description": "HTTP Content routing, RAM cache, National", - "lastUpdated": "2018-03-02T19:13:46.808911+00:00", "name": "HTTP_LIVE_NATNL", "useInTable": "deliveryservice" }, { "description": "Ops hosts for management", - "lastUpdated": "2018-03-02T19:13:46.810576+00:00", "name": "TOOLS_SERVER", "useInTable": "server" }, { "description": "Path regular expression", - "lastUpdated": "2018-03-02T19:13:46.812049+00:00", "name": "PATH_REGEXP", "useInTable": "regex" }, { "description": "Static DNS CNAME entry", - "lastUpdated": "2018-03-02T19:13:46.813461+00:00", "name": "CNAME_RECORD", "useInTable": "staticdnsentry" }, { "description": "Kabletown Content Router", - "lastUpdated": "2018-03-02T19:13:46.814833+00:00", "name": "CCR", "useInTable": "server" }, { "description": "Origin Cachegroup", - "lastUpdated": "2018-03-02T19:13:46.816199+00:00", "name": "ORG_LOC", "useInTable": "cachegroup" }, { "description": "Mid Cachegroup", - "lastUpdated": "2018-03-02T19:13:46.816199+00:00", "name": "MID_LOC", "useInTable": "cachegroup" }, { "description": "Edge Cache", - "lastUpdated": "2018-03-02T19:13:46.817689+00:00", "name": "EDGE", "useInTable": "server" }, { "description": "Ordered steering target", - "lastUpdated": "2018-03-02T19:13:46.81913+00:00", "name": "STEERING_ORDER", "useInTable": "steering_target" }, { "description": "DNS Content Routing", - "lastUpdated": "2018-03-02T19:13:46.820528+00:00", "name": "DNS", "useInTable": "deliveryservice" }, { "description": "federation type resolve6", - "lastUpdated": "2018-03-02T19:13:46.822161+00:00", "name": "RESOLVE6", "useInTable": "federation" }, { "description": "Static DNS AAAA entry", - "lastUpdated": "2018-03-02T19:13:46.823506+00:00", "name": "AAAA_RECORD", "useInTable": "staticdnsentry" }, { "description": "HTTP Content Routing, no caching", - "lastUpdated": "2018-03-02T19:13:46.824798+00:00", "name": "HTTP_NO_CACHE", "useInTable": "deliveryservice" }, { "description": "any_map type", - "lastUpdated": "2018-03-02T19:13:46.826411+00:00", "name": "ANY_MAP", "useInTable": "deliveryservice" }, { "description": "Steering Delivery Service", - "lastUpdated": "2018-03-02T19:13:46.827779+00:00", "name": "STEERING", "useInTable": "deliveryservice" }, { "description": "Edge Cachegroup", - "lastUpdated": "2018-03-02T19:13:46.829249+00:00", "name": "EDGE_LOC", "useInTable": "cachegroup" }, { "description": "HTTP Content routing cache ", - "lastUpdated": "2018-03-02T19:13:46.830862+00:00", "name": "HTTP", "useInTable": "deliveryservice" }, { "description": "Mid Tier Cache", - "lastUpdated": "2018-03-02T19:13:46.832327+00:00", "name": "MID", "useInTable": "server" }, { "description": "Traffic Monitor (Rascal)", - "lastUpdated": "2018-03-02T19:13:46.832327+00:00", "name": "RASCAL", "useInTable": "server" } From 37215d73d0a1b22eb5e6869bd95140447dcc8a77 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 17:21:00 -0600 Subject: [PATCH 14/34] Update /deliveryservices documentation --- docs/source/api/v4/deliveryservices.rst | 489 ++++++++++++++---------- 1 file changed, 286 insertions(+), 203 deletions(-) diff --git a/docs/source/api/v4/deliveryservices.rst b/docs/source/api/v4/deliveryservices.rst index db62e945de..fb7f67698f 100644 --- a/docs/source/api/v4/deliveryservices.rst +++ b/docs/source/api/v4/deliveryservices.rst @@ -69,6 +69,17 @@ Request Structure | active | no | Show only the :term:`Delivery Services` that have :ref:`ds-active` set or not based on this boolean (whether or not they are active) | +-------------------+----------+-----------------------------------------------------------------------------------------------------------------------------------------+ +.. code-block:: http + :caption: Request Example + + GET /api/4.0/deliveryservices?xmlId=demo2 HTTP/1.1 + Host: trafficops.infra.ciab.test + User-Agent: python-requests/2.24.0 + Accept-Encoding: gzip, deflate + Accept: */* + Connection: keep-alive + Cookie: mojolicious=... + Response Structure ------------------ :active: A boolean that defines :ref:`ds-active`. @@ -104,10 +115,14 @@ Response Structure :innerHeaderRewrite: A set of :ref:`ds-inner-header-rw-rules` :ipv6RoutingEnabled: A boolean that defines the :ref:`ds-ipv6-routing` setting on this :term:`Delivery Service` :lastHeaderRewrite: A set of :ref:`ds-last-header-rw-rules` -:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :ref:`non-rfc-datetime` -:logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` -:longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` -:matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` +:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :rfc:3339 format + + .. versionchanged:: 4.0 + Prior to API version 4.0, this property used :ref:`non-rfc-datetime`. + +:logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` +:longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` +:matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` :pattern: A regular expression - the use of this pattern is dependent on the ``type`` field (backslashes are escaped) :setNumber: An integer that provides explicit ordering of :ref:`ds-matchlist` items - this is used as a priority ranking by Traffic Router, and is not guaranteed to correspond to the ordering of items in the array. @@ -137,12 +152,16 @@ Response Structure :rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. :sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` :tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` -:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to -:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` -:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` -:type: The :ref:`ds-types` of this :term:`Delivery Service` -:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` -:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` +:tlsVersions: A list of explicitly supported :ref:`ds-tls-versions` + + .. versionadded:: 4.0 + +:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to +:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` +:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` +:type: The :ref:`ds-types` of this :term:`Delivery Service` +:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` +:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` .. code-block:: http :caption: Response Example @@ -152,99 +171,98 @@ Response Structure Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Access-Control-Allow-Origin: * + Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: mCLMjvACRKHNGP/OSx4javkOtxxzyiDdQzsV78IamUhVmvyKyKaCeOKRmpsG69w+nhh3OkPZ6e9MMeJpcJSKcA== + Permissions-Policy: interest-cohort=() + Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 07 Jun 2021 22:52:20 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding X-Server-Name: traffic_ops_golang/ - Date: Thu, 15 Nov 2018 19:04:29 GMT - Transfer-Encoding: chunked + Date: Mon, 07 Jun 2021 21:52:20 GMT + Content-Length: 847 - { "response": [{ - "active": true, - "anonymousBlockingEnabled": false, - "cacheurl": null, - "ccrDnsTtl": null, - "cdnId": 2, - "cdnName": "CDN-in-a-Box", - "checkPath": null, - "displayName": "Demo 1", - "dnsBypassCname": null, - "dnsBypassIp": null, - "dnsBypassIp6": null, - "dnsBypassTtl": null, - "dscp": 0, - "edgeHeaderRewrite": null, - "firstHeaderRewrite": null, - "geoLimit": 0, - "geoLimitCountries": null, - "geoLimitRedirectURL": null, - "geoProvider": 0, - "globalMaxMbps": null, - "globalMaxTps": null, - "httpBypassFqdn": null, - "id": 1, - "infoUrl": null, - "initialDispersion": 1, - "innerHeaderRewrite": null, - "ipv6RoutingEnabled": true, - "lastHeaderRewrite": null, - "lastUpdated": "2019-05-15 14:32:05+00", - "logsEnabled": true, - "longDesc": "Apachecon North America 2018", - "matchList": [ - { - "type": "HOST_REGEXP", - "setNumber": 0, - "pattern": ".*\\.demo1\\..*" - } - ], - "maxDnsAnswers": null, - "midHeaderRewrite": null, - "missLat": 42, - "missLong": -88, - "multiSiteOrigin": false, - "originShield": null, - "orgServerFqdn": "http://origin.infra.ciab.test", - "profileDescription": null, - "profileId": null, - "profileName": null, - "protocol": 2, - "qstringIgnore": 0, - "rangeRequestHandling": 0, - "regexRemap": null, - "regionalGeoBlocking": false, - "remapText": null, - "routingName": "video", - "signed": false, - "sslKeyVersion": null, - "tenantId": 1, - "type": "HTTP", - "typeId": 1, - "xmlId": "demo1", - "exampleURLs": [ - "http://video.demo1.mycdn.ciab.test", - "https://video.demo1.mycdn.ciab.test" - ], - "deepCachingType": "NEVER", - "fqPacingRate": null, - "signingAlgorithm": null, - "tenant": "root", - "trResponseHeaders": null, - "trRequestHeaders": null, - "consistentHashRegex": null, - "consistentHashQueryParams": [ - "abc", - "pdq", - "xxx", - "zyx" - ], - "maxOriginConnections": 0, - "maxRequestHeaderBytes": 131072, - "ecsEnabled": false, - "rangeSliceBlockSize": null, - "topology": null - "serviceCategory": null - }]} + { "response": [ + { + "active": true, + "anonymousBlockingEnabled": false, + "ccrDnsTtl": null, + "cdnId": 2, + "cdnName": "CDN-in-a-Box", + "checkPath": null, + "consistentHashQueryParams": [], + "consistentHashRegex": null, + "deepCachingType": "NEVER", + "displayName": "Demo 2", + "dnsBypassCname": null, + "dnsBypassIp": null, + "dnsBypassIp6": null, + "dnsBypassTtl": null, + "dscp": 0, + "ecsEnabled": false, + "edgeHeaderRewrite": null, + "exampleURLs": [ + "http://video.demo2.mycdn.ciab.test", + "https://video.demo2.mycdn.ciab.test" + ], + "firstHeaderRewrite": null, + "fqPacingRate": null, + "geoLimit": 0, + "geoLimitCountries": null, + "geoLimitRedirectURL": null, + "geoProvider": 0, + "globalMaxMbps": null, + "globalMaxTps": null, + "httpBypassFqdn": null, + "id": 1, + "infoUrl": null, + "initialDispersion": 1, + "innerHeaderRewrite": null, + "ipv6RoutingEnabled": true, + "lastHeaderRewrite": null, + "lastUpdated": "2021-06-07T21:50:03.009954Z", + "logsEnabled": true, + "longDesc": "DNS Delivery Service for use with a Federation", + "matchList": [ + { + "type": "HOST_REGEXP", + "setNumber": 0, + "pattern": ".*\\.demo2\\..*" + } + ], + "maxDnsAnswers": null, + "maxOriginConnections": 0, + "maxRequestHeaderBytes": 0, + "midHeaderRewrite": null, + "missLat": 42, + "missLong": -88, + "multiSiteOrigin": true, + "originShield": null, + "orgServerFqdn": "http://origin.infra.ciab.test", + "profileDescription": null, + "profileId": null, + "profileName": null, + "protocol": 2, + "qstringIgnore": 0, + "rangeRequestHandling": 0, + "rangeSliceBlockSize": null, + "regexRemap": null, + "regionalGeoBlocking": false, + "remapText": null, + "routingName": "video", + "serviceCategory": null, + "signed": false, + "signingAlgorithm": null, + "sslKeyVersion": null, + "tenant": "root", + "tenantId": 1, + "tlsVersions": null, + "topology": "demo1-top", + "trResponseHeaders": null, + "trRequestHeaders": null, + "type": "DNS", + "typeId": 5, + "xmlId": "demo2" + } + ]} ``POST`` @@ -308,56 +326,99 @@ Request Structure :serviceCategory: The name of the :ref:`ds-service-category` with which the :term:`Delivery Service` is associated - or ``null`` if there is to be no such category :signed: ``true`` if and only if ``signingAlgorithm`` is not ``null``, ``false`` otherwise :signingAlgorithm: Either a :ref:`ds-signing-algorithm` or ``null`` to indicate URL/URI signing is not implemented on this :term:`Delivery Service` -:rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. It can only be between (inclusive) 262144 (256KB) - 33554432 (32MB). +:rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. It can only be between (inclusive) 262144 (256KB) - 33554432 (32MB). :sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` :tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` -:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to -:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` -:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` -:type: The :ref:`ds-types` of this :term:`Delivery Service` -:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` -:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` +:tlsVersions: An array of explicitly supported :ref:`ds-tls-versions` + + .. versionadded:: 4.0 + +:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to +:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` +:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` +:type: The :ref:`ds-types` of this :term:`Delivery Service` +:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` +:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` .. code-block:: http :caption: Request Example POST /api/4.0/deliveryservices HTTP/1.1 - Host: trafficops.infra.ciab.test - User-Agent: curl/7.47.0 + User-Agent: python-requests/2.24.0 + Accept-Encoding: gzip, deflate Accept: */* + Connection: keep-alive Cookie: mojolicious=... - Content-Length: 761 + Content-Length: 1602 Content-Type: application/json + Host: trafficops.infra.ciab.test { "active": false, "anonymousBlockingEnabled": false, + "ccrDnsTtl": null, "cdnId": 2, + "checkPath": null, + "consistentHashRegex": null, + "consistentHashQueryParams": [], "deepCachingType": "NEVER", "displayName": "test", + "dnsBypassCname": null, + "dnsBypassIp": null, + "dnsBypassIp6": null, + "dnsBypassTtl": null, "dscp": 0, "ecsEnabled": true, + "edgeHeaderRewrite": null, + "firstHeaderRewrite": null, + "fqPacingRate": null, "geoLimit": 0, + "geoLimitCountries": null, + "geoLimitRedirectUrl": null, "geoProvider": 0, + "globalMaxMbps": null, + "globalMaxTps": null, + "httpBypassFqdn": null, + "infoUrl": null, "initialDispersion": 1, + "innerHeaderRewrite": null, "ipv6RoutingEnabled": false, + "lastHeaderRewrite": null, "logsEnabled": true, "longDesc": "A Delivery Service created expressly for API documentation examples", + "longDesc1": null, + "longDesc2": null, + "maxDnsAnswers": null, "missLat": 0, "missLong": 0, "maxOriginConnections": 0, "maxRequestHeaderBytes": 131072, + "midHeaderRewrite": null, "multiSiteOrigin": false, "orgServerFqdn": "http://origin.infra.ciab.test", + "originShield": null, + "profileId": null, "protocol": 0, "qstringIgnore": 0, "rangeRequestHandling": 0, + "regexRemap": null, "regionalGeoBlocking": false, "routingName": "test", "serviceCategory": null, "signed": false, + "signingAlgorithm": null, + "rangeSliceBlockSize": null, + "sslKeyVersion": null, "tenant": "root", "tenantId": 1, + "tlsVersions": [ + "1.2", + "1.3" + ], + "topology": null, + "trRequestHeaders": null, + "trResponseHeaders": null, + "type": "HTTP", "typeId": 1, "xmlId": "test" } @@ -398,10 +459,14 @@ Response Structure :innerHeaderRewrite: A set of :ref:`ds-inner-header-rw-rules` :ipv6RoutingEnabled: A boolean that defines the :ref:`ds-ipv6-routing` setting on this :term:`Delivery Service` :lastHeaderRewrite: A set of :ref:`ds-last-header-rw-rules` -:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :ref:`non-rfc-datetime` -:logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` -:longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` -:matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` +:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :rfc:3339 format + + .. versionchanged:: 4.0 + Prior to API version 4.0, this property used :ref:`non-rfc-datetime`. + +:logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` +:longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` +:matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` :pattern: A regular expression - the use of this pattern is dependent on the ``type`` field (backslashes are escaped) :setNumber: An integer that provides explicit ordering of :ref:`ds-matchlist` items - this is used as a priority ranking by Traffic Router, and is not guaranteed to correspond to the ordering of items in the array. @@ -431,111 +496,129 @@ Response Structure :rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. :sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` :tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` -:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to -:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` -:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` -:type: The :ref:`ds-types` of this :term:`Delivery Service` -:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` -:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` +:tlsVersions: An array of explicitly supported :ref:`ds-tls-versions` + + .. versionadded:: 4.0 + +:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to +:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` +:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` +:type: The :ref:`ds-types` of this :term:`Delivery Service` +:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` +:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` .. code-block:: http :caption: Response Example - HTTP/1.1 200 OK + HTTP/1.1 201 Created Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Access-Control-Allow-Origin: * + Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: SVveQ5hGwfPv8N5APUskwLOzwrTUVA+z8wuFLsSLCr1/vVnFJJ0VQOGMUctg1NbqhAuQ795MJmuuAaAwR8dSOQ== + Location: /api/4.0/deliveryservices?id=6 + Permissions-Policy: interest-cohort=() + Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 07 Jun 2021 23:37:37 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding X-Server-Name: traffic_ops_golang/ - Date: Mon, 19 Nov 2018 19:45:49 GMT - Content-Length: 1404 + Date: Mon, 07 Jun 2021 22:37:37 GMT + Content-Length: 903 { "alerts": [ { - "text": "Deliveryservice creation was successful.", + "text": "tlsVersions has no effect on 'HTTP' Delivery Services", + "level": "warning" + }, + { + "text": "Delivery Service creation was successful", "level": "success" } ], - "response": [ - { - "active": false, - "anonymousBlockingEnabled": false, - "cacheurl": null, - "ccrDnsTtl": null, - "cdnId": 2, - "cdnName": "CDN-in-a-Box", - "checkPath": null, - "displayName": "test", - "dnsBypassCname": null, - "dnsBypassIp": null, - "dnsBypassIp6": null, - "dnsBypassTtl": null, - "dscp": 0, - "edgeHeaderRewrite": null, - "firstHeaderRewrite": null, - "geoLimit": 0, - "geoLimitCountries": null, - "geoLimitRedirectURL": null, - "geoProvider": 0, - "globalMaxMbps": null, - "globalMaxTps": null, - "httpBypassFqdn": null, - "id": 2, - "infoUrl": null, - "initialDispersion": 1, - "innerHeaderRewrite": null, - "ipv6RoutingEnabled": false, - "lastHeaderRewrite": null, - "lastUpdated": "2018-11-19 19:45:49+00", - "logsEnabled": true, - "longDesc": "A Delivery Service created expressly for API documentation examples", - "matchList": [ - { - "type": "HOST_REGEXP", - "setNumber": 0, - "pattern": ".*\\.test\\..*" - } - ], - "maxDnsAnswers": null, - "maxOriginConnections": 0, - "maxRequestHeaderBytes": 131072, - "midHeaderRewrite": null, - "missLat": -1, - "missLong": -1, - "multiSiteOrigin": false, - "originShield": null, - "orgServerFqdn": "http://origin.infra.ciab.test", - "profileDescription": null, - "profileId": null, - "profileName": null, - "protocol": 0, - "qstringIgnore": 0, - "rangeRequestHandling": 0, - "regexRemap": null, - "regionalGeoBlocking": false, - "remapText": null, - "routingName": "test", - "serviceCategory": null, - "signed": false, - "sslKeyVersion": null, - "tenantId": 1, - "type": "HTTP", - "typeId": 1, - "xmlId": "test", - "exampleURLs": [ - "http://test.test.mycdn.ciab.test" - ], - "deepCachingType": "NEVER", - "signingAlgorithm": null, - "tenant": "root", - "ecsEnabled": true, - "rangeSliceBlockSize": null, - "topology": null - } - ]} + "response": [{ + "active": false, + "anonymousBlockingEnabled": false, + "ccrDnsTtl": null, + "cdnId": 2, + "cdnName": null, + "checkPath": null, + "consistentHashQueryParams": [], + "consistentHashRegex": null, + "deepCachingType": "NEVER", + "displayName": "test", + "dnsBypassCname": null, + "dnsBypassIp": null, + "dnsBypassIp6": null, + "dnsBypassTtl": null, + "dscp": 0, + "ecsEnabled": true, + "edgeHeaderRewrite": null, + "exampleURLs": [ + "http://test.test.mycdn.ciab.test" + ], + "firstHeaderRewrite": null, + "fqPacingRate": null, + "geoLimit": 0, + "geoLimitCountries": null, + "geoLimitRedirectURL": null, + "geoProvider": 0, + "globalMaxMbps": null, + "globalMaxTps": null, + "httpBypassFqdn": null, + "id": 6, + "infoUrl": null, + "initialDispersion": 1, + "innerHeaderRewrite": null, + "ipv6RoutingEnabled": false, + "lastHeaderRewrite": null, + "lastUpdated": "2021-06-07T22:37:37.187822Z", + "logsEnabled": true, + "longDesc": "A Delivery Service created expressly for API documentation examples", + "matchList": [ + { + "type": "HOST_REGEXP", + "setNumber": 0, + "pattern": ".*\\.test\\..*" + } + ], + "maxDnsAnswers": null, + "maxOriginConnections": 0, + "maxRequestHeaderBytes": 131072, + "midHeaderRewrite": null, + "missLat": 0, + "missLong": 0, + "multiSiteOrigin": false, + "originShield": null, + "orgServerFqdn": "http://origin.infra.ciab.test", + "profileDescription": null, + "profileId": null, + "profileName": null, + "protocol": 0, + "qstringIgnore": 0, + "rangeRequestHandling": 0, + "rangeSliceBlockSize": null, + "regexRemap": null, + "regionalGeoBlocking": false, + "remapText": null, + "routingName": "test", + "serviceCategory": null, + "signed": false, + "signingAlgorithm": null, + "sslKeyVersion": null, + "tenant": "root", + "tenantId": 1, + "tlsVersions": [ + "1.2", + "1.3" + ], + "topology": null, + "trResponseHeaders": null, + "trRequestHeaders": null, + "type": "HTTP", + "typeId": 1, + "xmlId": "test" + }]} + .. [#tenancy] Only those :term:`Delivery Services` assigned to :term:`Tenants` that are the requesting user's :term:`Tenant` or children thereof will appear in the output of a ``GET`` request, and the same constraints are placed on the allowed values of the ``tenantId`` field of a ``POST`` request to create a new :term:`Delivery Service` .. [#geoLimit] These fields must be defined if and only if ``geoLimit`` is non-zero From a8d2549b96c3d7f0fd4f4ea2a6c74c52937ca337 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 17:42:54 -0600 Subject: [PATCH 15/34] Update /deliveryservices/{{ID}} documentation --- docs/source/api/v4/deliveryservices_id.rst | 270 ++++++++++++++++++--- 1 file changed, 242 insertions(+), 28 deletions(-) diff --git a/docs/source/api/v4/deliveryservices_id.rst b/docs/source/api/v4/deliveryservices_id.rst index 8cfe3352a9..259792d8ea 100644 --- a/docs/source/api/v4/deliveryservices_id.rst +++ b/docs/source/api/v4/deliveryservices_id.rst @@ -25,7 +25,7 @@ Allows users to edit an existing :term:`Delivery Service`. :Auth. Required: Yes :Roles Required: "admin" or "operations"\ [#tenancy]_ -:Response Type: **NOT PRESENT** - Despite returning a ``200 OK`` response (rather than e.g. a ``204 NO CONTENT`` response), this endpoint does **not** return a representation of the modified resource in its payload, and instead returns nothing - not even a success message. +:Response Type: Array (should always have a length of exactly one on success) Request Structure ----------------- @@ -81,18 +81,22 @@ Request Structure :remapText: :ref:`ds-raw-remap` :routingName: The :ref:`ds-routing-name` of this :term:`Delivery Service` - .. note:: If the Delivery Service has SSL Keys, then routingName is not allowed to change as that would invalidate the SSL Key + .. note:: If the Delivery Service has SSL Keys, then ``routingName`` is not allowed to change as that would invalidate the SSL Key -:signed: ``true`` if and only if ``signingAlgorithm`` is not ``null``, ``false`` otherwise -:signingAlgorithm: Either a :ref:`ds-signing-algorithm` or ``null`` to indicate URL/URI signing is not implemented on this :term:`Delivery Service` -:rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. It can only be between (inclusive) 262144 (256KB) - 33554432 (32MB). -:sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` -:tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` -:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to -:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` -:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` -:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` -:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` +:signed: ``true`` if and only if ``signingAlgorithm`` is not ``null``, ``false`` otherwise +:signingAlgorithm: Either a :ref:`ds-signing-algorithm` or ``null`` to indicate URL/URI signing is not implemented on this :term:`Delivery Service` +:rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. It can only be between (inclusive) 262144 (256KB) - 33554432 (32MB). +:sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` +:tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` +:tlsVersions: An array of explicitly supported :ref:`ds-tls-versions` + + .. versionadded:: 4.0 + +:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to +:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` +:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` +:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` +:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` .. note:: While this field **must** be present, it is **not** allowed to change; this must be the same as the ``xml_id`` the :term:`Delivery Service` already has. This should almost never be different from the :term:`Delivery Service`'s ``displayName``. @@ -100,49 +104,169 @@ Request Structure .. code-block:: http :caption: Request Example - PUT /api/4.0/deliveryservices/1 HTTP/1.1 + PUT /api/4.0/deliveryservices/6 HTTP/1.1 Host: trafficops.infra.ciab.test - User-Agent: curl/7.47.0 + User-Agent: python-requests/2.24.0 + Accept-Encoding: gzip, deflate Accept: */* + Connection: keep-alive Cookie: mojolicious=... - Content-Length: 761 + Content-Length: 1585 Content-Type: application/json { - "active": true, + "active": false, "anonymousBlockingEnabled": false, + "ccrDnsTtl": null, "cdnId": 2, - "cdnName": "CDN-in-a-Box", + "checkPath": null, + "consistentHashRegex": null, + "consistentHashQueryParams": [], "deepCachingType": "NEVER", - "displayName": "demo", + "displayName": "test", + "dnsBypassCname": null, + "dnsBypassIp": null, + "dnsBypassIp6": null, + "dnsBypassTtl": null, "dscp": 0, "ecsEnabled": true, + "edgeHeaderRewrite": null, + "firstHeaderRewrite": null, + "fqPacingRate": null, "geoLimit": 0, + "geoLimitCountries": null, + "geoLimitRedirectUrl": null, "geoProvider": 0, + "globalMaxMbps": null, + "globalMaxTps": null, + "httpBypassFqdn": null, + "infoUrl": null, "initialDispersion": 1, + "innerHeaderRewrite": null, "ipv6RoutingEnabled": false, - "lastUpdated": "2018-11-14 18:21:17+00", + "lastHeaderRewrite": null, "logsEnabled": true, "longDesc": "A Delivery Service created expressly for API documentation examples", - "missLat": -1, - "missLong": -1, + "longDesc1": null, + "longDesc2": null, + "maxDnsAnswers": null, + "missLat": 0, + "missLong": 0, + "maxOriginConnections": 0, + "maxRequestHeaderBytes": 131072, + "midHeaderRewrite": null, "multiSiteOrigin": false, "orgServerFqdn": "http://origin.infra.ciab.test", + "originShield": null, + "profileId": null, "protocol": 0, "qstringIgnore": 0, "rangeRequestHandling": 0, + "regexRemap": null, "regionalGeoBlocking": false, - "routingName": "video", + "routingName": "test", + "serviceCategory": null, "signed": false, + "signingAlgorithm": null, + "rangeSliceBlockSize": null, + "sslKeyVersion": null, "tenant": "root", "tenantId": 1, + "tlsVersions": null, + "topology": null, + "trRequestHeaders": null, + "trResponseHeaders": null, + "type": "HTTP", "typeId": 1, - "xmlId": "demo1" + "xmlId": "test" } Response Structure ------------------ +:active: A boolean that defines :ref:`ds-active`. +:anonymousBlockingEnabled: A boolean that defines :ref:`ds-anonymous-blocking` +:ccrDnsTtl: The :ref:`ds-dns-ttl` - named "ccrDnsTtl" for legacy reasons +:cdnId: The integral, unique identifier of the :ref:`ds-cdn` to which the :term:`Delivery Service` belongs +:cdnName: Name of the :ref:`ds-cdn` to which the :term:`Delivery Service` belongs +:checkPath: A :ref:`ds-check-path` +:consistentHashRegex: A :ref:`ds-consistent-hashing-regex` +:consistentHashQueryParams: An array of :ref:`ds-consistent-hashing-qparams` +:deepCachingType: The :ref:`ds-deep-caching` setting for this :term:`Delivery Service` +:displayName: The :ref:`ds-display-name` +:dnsBypassCname: A :ref:`ds-dns-bypass-cname` +:dnsBypassIp: A :ref:`ds-dns-bypass-ip` +:dnsBypassIp6: A :ref:`ds-dns-bypass-ipv6` +:dnsBypassTtl: The :ref:`ds-dns-bypass-ttl` +:dscp: A :ref:`ds-dscp` to be used within the :term:`Delivery Service` +:ecsEnabled: A boolean that defines the :ref:`ds-ecs` setting on this :term:`Delivery Service` +:edgeHeaderRewrite: A set of :ref:`ds-edge-header-rw-rules` +:exampleURLs: An array of :ref:`ds-example-urls` +:firstHeaderRewrite: A set of :ref:`ds-first-header-rw-rules` +:fqPacingRate: The :ref:`ds-fqpr` +:geoLimit: An integer that defines the :ref:`ds-geo-limit` +:geoLimitCountries: A string containing a comma-separated list defining the :ref:`ds-geo-limit-countries` +:geoLimitRedirectUrl: A :ref:`ds-geo-limit-redirect-url` +:geoProvider: The :ref:`ds-geo-provider` +:globalMaxMbps: The :ref:`ds-global-max-mbps` +:globalMaxTps: The :ref:`ds-global-max-tps` +:httpBypassFqdn: A :ref:`ds-http-bypass-fqdn` +:id: An integral, unique identifier for this :term:`Delivery Service` +:infoUrl: An :ref:`ds-info-url` +:initialDispersion: The :ref:`ds-initial-dispersion` +:innerHeaderRewrite: A set of :ref:`ds-inner-header-rw-rules` +:ipv6RoutingEnabled: A boolean that defines the :ref:`ds-ipv6-routing` setting on this :term:`Delivery Service` +:lastHeaderRewrite: A set of :ref:`ds-last-header-rw-rules` +:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :rfc:3339 format + + .. versionchanged:: 4.0 + Prior to API version 4.0, this property used :ref:`non-rfc-datetime`. + +:logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` +:longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` +:longDesc1: The :ref:`ds-longdesc2` of this :term:`Delivery Service` +:longDesc2: The :ref:`ds-longdesc3` of this :term:`Delivery Service` +:matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` + + :pattern: A regular expression - the use of this pattern is dependent on the ``type`` field (backslashes are escaped) + :setNumber: An integer that provides explicit ordering of :ref:`ds-matchlist` items - this is used as a priority ranking by Traffic Router, and is not guaranteed to correspond to the ordering of items in the array. + :type: The type of match performed using ``pattern``. + +:maxDnsAnswers: The :ref:`ds-max-dns-answers` allowed for this :term:`Delivery Service` +:maxOriginConnections: The :ref:`ds-max-origin-connections` +:maxRequestHeaderBytes: The :ref:`ds-max-request-header-bytes` +:midHeaderRewrite: A set of :ref:`ds-mid-header-rw-rules` +:missLat: The :ref:`ds-geo-miss-default-latitude` used by this :term:`Delivery Service` +:missLong: The :ref:`ds-geo-miss-default-longitude` used by this :term:`Delivery Service` +:multiSiteOrigin: A boolean that defines the use of :ref:`ds-multi-site-origin` by this :term:`Delivery Service` +:orgServerFqdn: The :ref:`ds-origin-url` +:originShield: A :ref:`ds-origin-shield` string +:profileDescription: The :ref:`profile-description` of the :ref:`ds-profile` with which this :term:`Delivery Service` is associated +:profileId: The :ref:`profile-id` of the :ref:`ds-profile` with which this :term:`Delivery Service` is associated +:profileName: The :ref:`profile-name` of the :ref:`ds-profile` with which this :term:`Delivery Service` is associated +:protocol: An integral, unique identifier that corresponds to the :ref:`ds-protocol` used by this :term:`Delivery Service` +:qstringIgnore: An integral, unique identifier that corresponds to the :ref:`ds-qstring-handling` setting on this :term:`Delivery Service` +:rangeRequestHandling: An integral, unique identifier that corresponds to the :ref:`ds-range-request-handling` setting on this :term:`Delivery Service` +:regexRemap: A :ref:`ds-regex-remap` +:regionalGeoBlocking: A boolean defining the :ref:`ds-regionalgeo` setting on this :term:`Delivery Service` +:remapText: :ref:`ds-raw-remap` +:serviceCategory: The name of the :ref:`ds-service-category` with which the :term:`Delivery Service` is associated +:signed: ``true`` if and only if ``signingAlgorithm`` is not ``null``, ``false`` otherwise +:signingAlgorithm: Either a :ref:`ds-signing-algorithm` or ``null`` to indicate URL/URI signing is not implemented on this :term:`Delivery Service` +:rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. +:sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` +:tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` +:tlsVersions: An array of explicitly supported :ref:`ds-tls-versions` + + .. versionadded:: 4.0 + +:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to +:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` +:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` +:type: The :ref:`ds-types` of this :term:`Delivery Service` +:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` +:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` + .. code-block:: http :caption: Response Example @@ -151,12 +275,102 @@ Response Structure Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Access-Control-Allow-Origin: * - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg== + Content-Encoding: gzip + Content-Type: application/json + Permissions-Policy: interest-cohort=() + Set-Cookie: mojolicious=...; Path=/; Expires=Tue, 08 Jun 2021 00:34:04 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding + Whole-Content-Sha512: tTncbRoJR+pyykVbEc6nWyoFnhlJzsbge9hVZfw+WK28rzSGECZ/Q4zXTQtFjHWY5G+0Rk4w9GKrSFK3k+u5Ng== X-Server-Name: traffic_ops_golang/ - Date: Tue, 20 Nov 2018 14:12:25 GMT - Content-Length: 0 - Content-Type: text/plain; charset=utf-8 + Date: Mon, 07 Jun 2021 23:34:04 GMT + Content-Length: 840 + + { "alerts": [ + { + "text": "Delivery Service update was successful", + "level": "success" + } + ], + "response": [{ + "active": false, + "anonymousBlockingEnabled": false, + "ccrDnsTtl": null, + "cdnId": 2, + "cdnName": null, + "checkPath": null, + "consistentHashQueryParams": [], + "consistentHashRegex": null, + "deepCachingType": "NEVER", + "displayName": "test", + "dnsBypassCname": null, + "dnsBypassIp": null, + "dnsBypassIp6": null, + "dnsBypassTtl": null, + "dscp": 0, + "ecsEnabled": true, + "edgeHeaderRewrite": null, + "exampleURLs": null, + "firstHeaderRewrite": null, + "fqPacingRate": null, + "geoLimit": 0, + "geoLimitCountries": null, + "geoLimitRedirectURL": null, + "geoProvider": 0, + "globalMaxMbps": null, + "globalMaxTps": null, + "httpBypassFqdn": null, + "id": 6, + "infoUrl": null, + "initialDispersion": 1, + "innerHeaderRewrite": null, + "ipv6RoutingEnabled": false, + "lastHeaderRewrite": null, + "lastUpdated": "2021-06-07T23:34:04.831215Z", + "logsEnabled": true, + "longDesc": "A Delivery Service created expressly for API documentation examples", + "longDesc1": null, + "longDesc2": null, + "matchList": [ + { + "type": "HOST_REGEXP", + "setNumber": 0, + "pattern": ".*\\.test\\..*" + } + ], + "maxDnsAnswers": null, + "maxOriginConnections": 0, + "maxRequestHeaderBytes": 131072, + "midHeaderRewrite": null, + "missLat": 0, + "missLong": 0, + "multiSiteOrigin": false, + "originShield": null, + "orgServerFqdn": "http://origin.infra.ciab.test", + "profileDescription": null, + "profileId": null, + "profileName": null, + "protocol": 0, + "qstringIgnore": 0, + "rangeRequestHandling": 0, + "rangeSliceBlockSize": null, + "regexRemap": null, + "regionalGeoBlocking": false, + "remapText": null, + "routingName": "test", + "serviceCategory": null, + "signed": false, + "signingAlgorithm": null, + "sslKeyVersion": null, + "tenant": "root", + "tenantId": 1, + "tlsVersions": null, + "topology": null, + "trResponseHeaders": null, + "trRequestHeaders": null, + "type": "HTTP", + "typeId": 1, + "xmlId": "test" + }]} ``DELETE`` From b52c9ebf0a30136b6373de4f9d6cb48ba83872d6 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 18:00:02 -0600 Subject: [PATCH 16/34] Update /deliveryservices/{{ID}}/safe documentation --- .../api/v4/deliveryservices_id_safe.rst | 197 +++++++++--------- 1 file changed, 101 insertions(+), 96 deletions(-) diff --git a/docs/source/api/v4/deliveryservices_id_safe.rst b/docs/source/api/v4/deliveryservices_id_safe.rst index 1e56b8847c..bf7c8dc218 100644 --- a/docs/source/api/v4/deliveryservices_id_safe.rst +++ b/docs/source/api/v4/deliveryservices_id_safe.rst @@ -51,6 +51,7 @@ Request Structure Connection: keep-alive Cookie: mojolicious=... Content-Length: 132 + Content-Type: application/json { "displayName": "test", @@ -93,7 +94,11 @@ Response Structure :innerHeaderRewrite: A set of :ref:`ds-inner-header-rw-rules` :ipv6RoutingEnabled: A boolean that defines the :ref:`ds-ipv6-routing` setting on this :term:`Delivery Service` :lastHeaderRewrite: A set of :ref:`ds-last-header-rw-rules` -:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :ref:`non-rfc-datetime` +:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :rfc:3339 format + + .. versionchanged:: 4.0 + Prior to API version 4.0, this property used :ref:`non-rfc-datetime`. + :logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` :longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` :matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` @@ -124,6 +129,10 @@ Response Structure :rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. :sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` :tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` +:tlsVersions: A list of explicitly supported :ref:`ds-tls-versions` + + .. versionadded:: 4.0 + :topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to :trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` :trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` @@ -137,102 +146,98 @@ Response Structure HTTP/1.1 200 OK Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 10 Feb 2020 16:33:03 GMT; Max-Age=3600; HttpOnly + Permissions-Policy: interest-cohort=() + Set-Cookie: mojolicious=...; Path=/; Expires=Tue, 08 Jun 2021 00:53:26 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding + Whole-Content-Sha512: Ys/SfWWijsXCNXEqZ84oldfyXTgMe8UE/wWb53VU39OH7kWOXF1BH5Hg7Y40nCgXoWEqcaBq5+WCZg0bYuJdAA== X-Server-Name: traffic_ops_golang/ - Date: Mon, 10 Feb 2020 15:33:03 GMT - Content-Length: 853 - - { "alerts": [ - { - "text": "Delivery Service safe update successful.", - "level": "success" - } - ], - "response": [ - { - "active": true, - "anonymousBlockingEnabled": false, - "cacheurl": null, - "ccrDnsTtl": null, - "cdnId": 2, - "cdnName": "CDN-in-a-Box", - "checkPath": null, - "displayName": "test", - "dnsBypassCname": null, - "dnsBypassIp": null, - "dnsBypassIp6": null, - "dnsBypassTtl": null, - "dscp": 0, - "edgeHeaderRewrite": null, - "firstHeaderRewrite": null, - "geoLimit": 0, - "geoLimitCountries": null, - "geoLimitRedirectURL": null, - "geoProvider": 0, - "globalMaxMbps": null, - "globalMaxTps": null, - "httpBypassFqdn": null, - "id": 1, - "infoUrl": "this is not even a real URL", - "initialDispersion": 1, - "innerHeaderRewrite": null, - "ipv6RoutingEnabled": true, - "lastHeaderRewrite": null, - "lastUpdated": "2020-02-10 15:33:03+00", - "logsEnabled": true, - "longDesc": "this is a description of the delivery service", - "matchList": [ - { - "type": "HOST_REGEXP", - "setNumber": 0, - "pattern": ".*\\.demo1\\..*" - } - ], - "maxDnsAnswers": null, - "midHeaderRewrite": null, - "missLat": 42, - "missLong": -88, - "multiSiteOrigin": false, - "originShield": null, - "orgServerFqdn": "http://origin.infra.ciab.test", - "profileDescription": null, - "profileId": null, - "profileName": null, - "protocol": 2, - "qstringIgnore": 0, - "rangeRequestHandling": 0, - "regexRemap": null, - "regionalGeoBlocking": false, - "remapText": null, - "routingName": "video", - "signed": false, - "sslKeyVersion": 1, - "tenantId": 1, - "type": "HTTP", - "typeId": 1, - "xmlId": "demo1", - "exampleURLs": [ - "http://video.demo1.mycdn.ciab.test", - "https://video.demo1.mycdn.ciab.test" - ], - "deepCachingType": "NEVER", - "fqPacingRate": null, - "signingAlgorithm": null, - "tenant": "root", - "trResponseHeaders": null, - "trRequestHeaders": null, - "consistentHashRegex": null, - "consistentHashQueryParams": [ - "abc", - "pdq", - "xxx", - "zyx" - ], - "maxOriginConnections": 0, - "ecsEnabled": false, - "rangeSliceBlockSize": null, - "topology": null - } + Date: Mon, 07 Jun 2021 23:53:26 GMT + Content-Length: 903 + + { "alerts": [{ + "text": "Delivery Service safe update successful.", + "level": "success" + }], + "response": [{ + "active": true, + "anonymousBlockingEnabled": false, + "ccrDnsTtl": null, + "cdnId": 2, + "cdnName": "CDN-in-a-Box", + "checkPath": null, + "consistentHashQueryParams": [], + "consistentHashRegex": null, + "deepCachingType": "NEVER", + "displayName": "test", + "dnsBypassCname": null, + "dnsBypassIp": null, + "dnsBypassIp6": null, + "dnsBypassTtl": null, + "dscp": 0, + "ecsEnabled": false, + "edgeHeaderRewrite": null, + "exampleURLs": [ + "http://video.demo2.mycdn.ciab.test", + "https://video.demo2.mycdn.ciab.test" + ], + "firstHeaderRewrite": null, + "fqPacingRate": null, + "geoLimit": 0, + "geoLimitCountries": null, + "geoLimitRedirectURL": null, + "geoProvider": 0, + "globalMaxMbps": null, + "globalMaxTps": null, + "httpBypassFqdn": null, + "id": 1, + "infoUrl": "this is not even a real URL", + "initialDispersion": 1, + "innerHeaderRewrite": null, + "ipv6RoutingEnabled": true, + "lastHeaderRewrite": null, + "lastUpdated": "2021-06-07T23:53:26.139899Z", + "logsEnabled": true, + "longDesc": "this is a description of the delivery service", + "matchList": [ + { + "type": "HOST_REGEXP", + "setNumber": 0, + "pattern": ".*\\.demo2\\..*" + } + ], + "maxDnsAnswers": null, + "maxOriginConnections": 0, + "maxRequestHeaderBytes": 0, + "midHeaderRewrite": null, + "missLat": 42, + "missLong": -88, + "multiSiteOrigin": true, + "originShield": null, + "orgServerFqdn": "http://origin.infra.ciab.test", + "profileDescription": null, + "profileId": null, + "profileName": null, + "protocol": 2, + "qstringIgnore": 0, + "rangeRequestHandling": 0, + "rangeSliceBlockSize": null, + "regexRemap": null, + "regionalGeoBlocking": false, + "remapText": null, + "routingName": "video", + "serviceCategory": null, + "signed": false, + "signingAlgorithm": null, + "sslKeyVersion": null, + "tenant": "root", + "tenantId": 1, + "tlsVersions": null, + "topology": "demo1-top", + "trResponseHeaders": null, + "trRequestHeaders": null, + "type": "DNS", + "typeId": 5, + "xmlId": "demo2" ]} .. [#tenancy] Only those :term:`Delivery Services` assigned to :term:`Tenants` that are the requesting user's :term:`Tenant` or children thereof may be modified with this endpoint. From 0f57db655ab9175b7abad4f803d277c757729d5b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 18:06:45 -0600 Subject: [PATCH 17/34] Update /deliveryservice_requests documentation --- .../api/v4/deliveryservice_requests.rst | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/source/api/v4/deliveryservice_requests.rst b/docs/source/api/v4/deliveryservice_requests.rst index 60edef2fd8..ce89718b01 100644 --- a/docs/source/api/v4/deliveryservice_requests.rst +++ b/docs/source/api/v4/deliveryservice_requests.rst @@ -135,7 +135,7 @@ The response is an array of representations of :term:`Delivery Service Requests` "innerHeaderRewrite": null, "ipv6RoutingEnabled": true, "lastHeaderRewrite": null, - "lastUpdated": "0001-01-01 00:00:00+00", + "lastUpdated": "0001-01-01T00:00:00Z", "logsEnabled": true, "longDesc": "Apachecon North America 2018", "matchList": [ @@ -187,7 +187,8 @@ The response is an array of representations of :term:`Delivery Service Requests` "zyx" ], "maxOriginConnections": 0, - "ecsEnabled": false + "ecsEnabled": false, + "tlsVersions": null }, "status": "draft" }]} @@ -249,7 +250,7 @@ The request must be a well-formed representation of a :term:`Delivery Service Re "innerHeaderRewrite": null, "ipv6RoutingEnabled": true, "lastHeaderRewrite": null, - "lastUpdated": "2020-02-13 16:43:54+00", + "lastUpdated": "2020-02-13T16:43:54Z", "logsEnabled": true, "longDesc": "Apachecon North America 2018", "matchList": [ @@ -302,7 +303,8 @@ The request must be a well-formed representation of a :term:`Delivery Service Re ], "maxOriginConnections": 0, "ecsEnabled": false, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null } } @@ -372,7 +374,7 @@ The response will be a representation of the created :term:`Delivery Service Req "innerHeaderRewrite": null, "ipv6RoutingEnabled": true, "lastHeaderRewrite": null, - "lastUpdated": "0001-01-01 00:00:00+00", + "lastUpdated": "0001-01-01T00:00:00Z", "logsEnabled": true, "longDesc": "Apachecon North America 2018", "matchList": [ @@ -424,7 +426,8 @@ The response will be a representation of the created :term:`Delivery Service Req "zyx" ], "maxOriginConnections": 0, - "ecsEnabled": false + "ecsEnabled": false, + "tlsVersions": null }, "original": { "active": true, @@ -455,7 +458,7 @@ The response will be a representation of the created :term:`Delivery Service Req "innerHeaderRewrite": null, "ipv6RoutingEnabled": true, "lastHeaderRewrite": null, - "lastUpdated": "2020-02-13 16:43:54+00", + "lastUpdated": "2020-02-13T16:43:54Z", "logsEnabled": true, "longDesc": "Apachecon North America 2018", "matchList": [ @@ -508,7 +511,8 @@ The response will be a representation of the created :term:`Delivery Service Req ], "maxOriginConnections": 0, "ecsEnabled": false, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null }, "status": "draft" } @@ -628,7 +632,7 @@ The response is a full representation of the edited :term:`Delivery Service Requ "infoUrl": null, "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2020-09-25 02:09:54+00", + "lastUpdated": "2020-09-25T02:09:54Z", "logsEnabled": true, "longDesc": "Apachecon North America 2018", "matchList": [ @@ -685,7 +689,8 @@ The response is a full representation of the edited :term:`Delivery Service Requ "firstHeaderRewrite": null, "innerHeaderRewrite": null, "lastHeaderRewrite": null, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null }, "requested": { "active": true, @@ -756,7 +761,8 @@ The response is a full representation of the edited :term:`Delivery Service Requ "firstHeaderRewrite": null, "innerHeaderRewrite": null, "lastHeaderRewrite": null, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null }, "status": "draft" }} From 6524edc5d18e4391006414fb511fa32bd312fc5a Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 18:09:55 -0600 Subject: [PATCH 18/34] Update /deliveryservice_requests/{{ID}}/status documentation --- docs/source/api/v4/deliveryservice_requests_id_status.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/api/v4/deliveryservice_requests_id_status.rst b/docs/source/api/v4/deliveryservice_requests_id_status.rst index d9821749cc..1ecd5f4e60 100644 --- a/docs/source/api/v4/deliveryservice_requests_id_status.rst +++ b/docs/source/api/v4/deliveryservice_requests_id_status.rst @@ -166,7 +166,7 @@ The response is a full representation of the modified :term:`DSR`. "infoUrl": null, "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2020-09-25 02:09:54+00", + "lastUpdated": "2020-09-25T02:09:54Z", "logsEnabled": true, "longDesc": "Apachecon North America 2018", "matchList": [ @@ -223,7 +223,8 @@ The response is a full representation of the modified :term:`DSR`. "firstHeaderRewrite": null, "innerHeaderRewrite": null, "lastHeaderRewrite": null, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null }, "requested": { "active": true, @@ -294,7 +295,8 @@ The response is a full representation of the modified :term:`DSR`. "firstHeaderRewrite": null, "innerHeaderRewrite": null, "lastHeaderRewrite": null, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null }, "status": "submitted" }} From 1b9780f47b1f68a8926a7d5fb0bb38d105362ebf Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 18:12:04 -0600 Subject: [PATCH 19/34] Update /deliveryservice_requests/{{ID}}/assign documentation --- docs/source/api/v4/deliveryservice_requests_id_assign.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/api/v4/deliveryservice_requests_id_assign.rst b/docs/source/api/v4/deliveryservice_requests_id_assign.rst index 4c6216aab1..8c7accea4d 100644 --- a/docs/source/api/v4/deliveryservice_requests_id_assign.rst +++ b/docs/source/api/v4/deliveryservice_requests_id_assign.rst @@ -169,7 +169,7 @@ The response contains a full representation of the newly assigned :term:`Deliver "infoUrl": null, "initialDispersion": 1, "ipv6RoutingEnabled": true, - "lastUpdated": "2020-09-25 02:09:54+00", + "lastUpdated": "2020-09-25T02:09:54Z", "logsEnabled": true, "longDesc": "Apachecon North America 2018", "matchList": [ @@ -226,7 +226,8 @@ The response contains a full representation of the newly assigned :term:`Deliver "firstHeaderRewrite": null, "innerHeaderRewrite": null, "lastHeaderRewrite": null, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null }, "requested": { "active": true, @@ -297,7 +298,8 @@ The response contains a full representation of the newly assigned :term:`Deliver "firstHeaderRewrite": null, "innerHeaderRewrite": null, "lastHeaderRewrite": null, - "serviceCategory": null + "serviceCategory": null, + "tlsVersions": null }, "status": "draft" }} From 366bdbc951439cd9cf367d4ae2a4ba98effc8eca Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 18:21:40 -0600 Subject: [PATCH 20/34] Update /servers/{{ID}}/deliveryservices documentation --- .../api/v4/servers_id_deliveryservices.rst | 111 ++++++++++-------- 1 file changed, 60 insertions(+), 51 deletions(-) diff --git a/docs/source/api/v4/servers_id_deliveryservices.rst b/docs/source/api/v4/servers_id_deliveryservices.rst index 529b3cb269..7add8a8837 100644 --- a/docs/source/api/v4/servers_id_deliveryservices.rst +++ b/docs/source/api/v4/servers_id_deliveryservices.rst @@ -59,10 +59,12 @@ Request Structure .. code-block:: http :caption: Request Example - GET /api/4.0/servers/9/deliveryservices HTTP/1.1 + GET /api/4.0/servers/10/deliveryservices HTTP/1.1 Host: trafficops.infra.ciab.test - User-Agent: curl/7.47.0 + User-Agent: python-requests/2.24.0 + Accept-Encoding: gzip, deflate Accept: */* + Connection: keep-alive Cookie: mojolicious=... Response Structure @@ -100,10 +102,14 @@ Response Structure :innerHeaderRewrite: A set of :ref:`ds-inner-header-rw-rules` :ipv6RoutingEnabled: A boolean that defines the :ref:`ds-ipv6-routing` setting on this :term:`Delivery Service` :lastHeaderRewrite: A set of :ref:`ds-last-header-rw-rules` -:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :ref:`non-rfc-datetime` -:logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` -:longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` -:matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` +:lastUpdated: The date and time at which this :term:`Delivery Service` was last updated, in :rfc:3339 format + + .. versionchanged:: 4.0 + Prior to API version 4.0, this property used :ref:`non-rfc-datetime`. + +:logsEnabled: A boolean that defines the :ref:`ds-logs-enabled` setting on this :term:`Delivery Service` +:longDesc: The :ref:`ds-longdesc` of this :term:`Delivery Service` +:matchList: The :term:`Delivery Service`'s :ref:`ds-matchlist` :pattern: A regular expression - the use of this pattern is dependent on the ``type`` field (backslashes are escaped) :setNumber: An integer that provides explicit ordering of :ref:`ds-matchlist` items - this is used as a priority ranking by Traffic Router, and is not guaranteed to correspond to the ordering of items in the array. @@ -131,12 +137,16 @@ Response Structure :rangeSliceBlockSize: An integer that defines the byte block size for the ATS Slice Plugin. It can only and must be set if ``rangeRequestHandling`` is set to 3. :sslKeyVersion: This integer indicates the :ref:`ds-ssl-key-version` :tenantId: The integral, unique identifier of the :ref:`ds-tenant` who owns this :term:`Delivery Service` -:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to -:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` -:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` -:type: The :ref:`ds-types` of this :term:`Delivery Service` -:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` -:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` +:tlsVersions: A list of explicitly supported :ref:`ds-tls-versions` + + .. versionadded:: 4.0 + +:topology: The unique name of the :term:`Topology` that this :term:`Delivery Service` is assigned to +:trRequestHeaders: If defined, this defines the :ref:`ds-tr-req-headers` used by Traffic Router for this :term:`Delivery Service` +:trResponseHeaders: If defined, this defines the :ref:`ds-tr-resp-headers` used by Traffic Router for this :term:`Delivery Service` +:type: The :ref:`ds-types` of this :term:`Delivery Service` +:typeId: The integral, unique identifier of the :ref:`ds-types` of this :term:`Delivery Service` +:xmlId: This :term:`Delivery Service`'s :ref:`ds-xmlid` .. code-block:: http :caption: Response Example @@ -146,29 +156,39 @@ Response Structure Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Access-Control-Allow-Origin: * + Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: CFmtW41aoDezCYxtAXnS54dfFOD6jdxDJ2/LMpbBqnndy5kac7JQhdFAWF109sl95XVSUV85JHFzXZTw/mJabQ== + Permissions-Policy: interest-cohort=() + Set-Cookie: mojolicious=...; Path=/; Expires=Tue, 08 Jun 2021 01:15:07 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding + Whole-Content-Sha512: RO4tVfDdqx0rEU9BqlRmvsYXmVgVNkivqr6LhJlMulfR+1bLGivP8z93jy3N9bejcMdQwl1RwJojM3MbwgXcqA== X-Server-Name: traffic_ops_golang/ - Date: Mon, 10 Jun 2019 17:01:30 GMT - Content-Length: 1500 + Date: Tue, 08 Jun 2021 00:15:07 GMT + Content-Length: 806 - { "response": [ { - "active": true, + { "response": [{ + "active": false, "anonymousBlockingEnabled": false, - "cacheurl": null, - "ccrDnsTtl": null, + "ccrDnsTtl": 3600, "cdnId": 2, "cdnName": "CDN-in-a-Box", "checkPath": null, - "displayName": "Demo 1", + "consistentHashQueryParams": [], + "consistentHashRegex": null, + "deepCachingType": "NEVER", + "displayName": "test", "dnsBypassCname": null, "dnsBypassIp": null, "dnsBypassIp6": null, "dnsBypassTtl": null, "dscp": 0, + "ecsEnabled": false, "edgeHeaderRewrite": null, + "exampleURLs": [ + "http://cdn.test.mycdn.ciab.test" + ], "firstHeaderRewrite": null, + "fqPacingRate": null, "geoLimit": 0, "geoLimitCountries": null, "geoLimitRedirectURL": null, @@ -176,66 +196,55 @@ Response Structure "globalMaxMbps": null, "globalMaxTps": null, "httpBypassFqdn": null, - "id": 1, + "id": 7, "infoUrl": null, "initialDispersion": 1, "innerHeaderRewrite": null, "ipv6RoutingEnabled": true, "lastHeaderRewrite": null, - "lastUpdated": "2019-06-10 15:14:29+00", - "logsEnabled": true, + "lastUpdated": "2021-06-08T00:14:04.959292Z", + "logsEnabled": false, "longDesc": "Apachecon North America 2018", "matchList": [ { "type": "HOST_REGEXP", "setNumber": 0, - "pattern": ".*\\.demo1\\..*" + "pattern": ".*\\.test\\..*" } ], "maxDnsAnswers": null, + "maxOriginConnections": 0, + "maxRequestHeaderBytes": 0, "midHeaderRewrite": null, - "missLat": 42, - "missLong": -88, + "missLat": 41.881944, + "missLong": -87.627778, "multiSiteOrigin": false, "originShield": null, "orgServerFqdn": "http://origin.infra.ciab.test", "profileDescription": null, "profileId": null, "profileName": null, - "protocol": 2, + "protocol": 0, "qstringIgnore": 0, "rangeRequestHandling": 0, + "rangeSliceBlockSize": null, "regexRemap": null, "regionalGeoBlocking": false, "remapText": null, - "routingName": "video", + "routingName": "cdn", + "serviceCategory": null, "signed": false, - "sslKeyVersion": 1, - "tenantId": 1, - "type": "HTTP", - "typeId": 1, - "xmlId": "demo1", - "exampleURLs": [ - "http://video.demo1.mycdn.ciab.test", - "https://video.demo1.mycdn.ciab.test" - ], - "deepCachingType": "NEVER", - "fqPacingRate": null, "signingAlgorithm": null, + "sslKeyVersion": null, "tenant": "root", + "tenantId": 1, + "tlsVersions": null, + "topology": null, "trResponseHeaders": null, "trRequestHeaders": null, - "consistentHashRegex": null, - "consistentHashQueryParams": [ - "abc", - "pdq", - "xxx", - "zyx" - ], - "maxOriginConnections": 0, - "ecsEnabled": false, - "rangeSliceBlockSize": null, - "topology": null + "type": "HTTP", + "typeId": 1, + "xmlId": "test" }]} From de6c80ced1eb9e1b1220804843bcd39711d2a604 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 18:35:51 -0600 Subject: [PATCH 21/34] Add section about TLS versions to the Delivery Service overview docs --- docs/source/overview/delivery_services.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/source/overview/delivery_services.rst b/docs/source/overview/delivery_services.rst index b489cb0aec..7591a6692d 100644 --- a/docs/source/overview/delivery_services.rst +++ b/docs/source/overview/delivery_services.rst @@ -795,6 +795,18 @@ The :term:`Tenant` who owns this Delivery Service. They (and their parents, if a | TenantID | Go code and :ref:`to-api` requests/responses | Integral, unique identifier (``bigint``, ``int`` etc.) | +----------+----------------------------------------------+--------------------------------------------------------+ +.. _ds-tls-versions: + +TLS Versions +------------ +The versions of TLS that can be used in HTTP requests to :term:`Edge-tier cache servers` for this Delivery Service's content can be limited using this property. When a Delivery Service has this property set to anything other than a ``null`` value, it lists the versions that will be allowed. Any versions can be added to the supported set, so long as they are of the form :samp:`{Major}.{Minor}`, e.g. ``1.1`` or ``42.0``. When this is a ``null`` value, no restrictions are placed on the TLS versions that may be used for retrieving Delivery Service content. + +.. impl-detail:: Traffic Ops will accept empty arrays as a synonym for ``null`` in requests, but will always represent them as ``null`` in responses. Note that this means it's impossible to create a Delivery Service that explicitly supports no TLS versions - the proper way to disable HTTPS for a Delivery Service is to set its Protocol_ accordingly. + +A Delivery Service that has a Type_ of ``STEERING`` or ``CLIENT_STEERING`` may not legally be set to have a TLS Versions property that is non-``null``. + +.. warning:: Using this setting may cause old clients that only support archaic TLS versions to break suddenly. Be sure that the security increase is worth this risk. + .. _ds-topology: Topology From 9fea661afc3560b9c46d002114d22de7cdb3403c Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 7 Jun 2021 18:49:18 -0600 Subject: [PATCH 22/34] Updated CHANGELOG --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c84f7204c..667e696f65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added `traffic_ops/app/db/traffic_vault_migrate` to help with migrating Traffic Ops Traffic Vault backends - Added a tool at `/traffic_ops/app/db/reencrypt` to re-encrypt the data in the Postgres Traffic Vault with a new key. - Enhanced ort integration test for reload states +- Added a new field to Delivery Services - `tlsVersions` - that explicitly lists the TLS versions that may be used to retrieve their content from Cache Servers. ### Fixed - [#5690](https://github.com/apache/trafficcontrol/issues/5690) - Fixed github action for added/modified db migration file. @@ -76,7 +77,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - [#5965](https://github.com/apache/trafficcontrol/issues/5965) - Fixed Traffic Ops /deliveryserviceservers If-Modified-Since requests. - Fixed t3c to create config files and directories as ats.ats - Fixed t3c-apply service restart and ats config reload logic. -- Reduced TR dns.max-threads ansible default from 10000 to 100. +- Reduced TR dns.max-threads ansible default from 10000 to 100. +- [#5981](https://github.com/apache/trafficcontrol/issues/5891) - `/deliveryservices/{{ID}}/safe` returns incorrect response for the requested API version +- [#5984](https://github.com/apache/trafficcontrol/issues/5894) - `/servers/{{ID}}/deliveryservices` returns incorrect response for the requested API version ### Changed - Updated the Traffic Ops Python client to 3.0 From 9ae9895ccd43dadeb7d775fc8f61ff195e39f1c1 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 9 Jun 2021 17:03:38 -0600 Subject: [PATCH 23/34] Revert non-nullable DS fields --- .../cdn-in-a-box/enroller/enroller.go | 4 +- lib/go-tc/deliveryservice_requests.go | 16 +- lib/go-tc/deliveryservice_requests_test.go | 5 +- lib/go-tc/deliveryservices.go | 151 ++---- lib/go-tc/deliveryservices_test.go | 30 +- .../v4/cachegroupsdeliveryservices_test.go | 8 +- .../deliveryservice_request_comments_test.go | 12 +- .../api/v4/deliveryservice_requests_test.go | 93 ++-- .../testing/api/v4/deliveryservices_test.go | 435 +++++++++++------- .../api/v4/deliveryserviceservers_test.go | 23 +- .../testing/api/v4/federations_test.go | 4 +- traffic_ops/testing/api/v4/jobs_test.go | 15 +- traffic_ops/testing/api/v4/servers_test.go | 6 +- ...vers_to_deliveryservice_assignment_test.go | 11 +- traffic_ops/testing/api/v4/tenants_test.go | 17 +- .../api/v4/topologies_queue_update_test.go | 6 +- traffic_ops/testing/api/v4/topologies_test.go | 8 +- .../dbhelpers/db_helpers.go | 5 +- .../deliveryservice/deliveryservices.go | 240 +++++----- .../deliveryservice/request/requests.go | 12 +- .../deliveryservice/request/validate.go | 4 +- .../deliveryservice/safe.go | 2 +- .../deliveryservice/servers/delete.go | 17 +- traffic_ops/v4-client/deliveryservice.go | 12 +- .../v4-client/deliveryservice_requests.go | 12 +- 25 files changed, 622 insertions(+), 526 deletions(-) diff --git a/infrastructure/cdn-in-a-box/enroller/enroller.go b/infrastructure/cdn-in-a-box/enroller/enroller.go index 8f091d5e7f..47769e1a6c 100644 --- a/infrastructure/cdn-in-a-box/enroller/enroller.go +++ b/infrastructure/cdn-in-a-box/enroller/enroller.go @@ -227,7 +227,7 @@ func enrollDeliveryService(toSession *session, r io.Reader) error { if err != nil { for _, alert := range alerts.Alerts.Alerts { if strings.Contains(alert.Text, "already exists") { - log.Infof("Delivery Service '%s' already exists", s.XMLID) + log.Infof("Delivery Service '%s' already exists", *s.XMLID) return nil } } @@ -827,7 +827,7 @@ func enrollFederation(toSession *session, r io.Reader) error { return err } deliveryService := deliveryServices.Response[0] - if deliveryService.CDNName == nil || deliveryService.ID == nil { + if deliveryService.CDNName == nil || deliveryService.ID == nil || deliveryService.XMLID == nil { err = fmt.Errorf("Delivery Service '%s' as returned from Traffic Ops had null or undefined CDN name and/or ID", xmlID) log.Infoln(err) return err diff --git a/lib/go-tc/deliveryservice_requests.go b/lib/go-tc/deliveryservice_requests.go index b48e30531f..c1bab3d4a7 100644 --- a/lib/go-tc/deliveryservice_requests.go +++ b/lib/go-tc/deliveryservice_requests.go @@ -798,12 +798,12 @@ func (dsr DeliveryServiceRequestV40) Downgrade() DeliveryServiceRequestNullable if dsr.XMLID != "" { downgraded.XMLID = new(string) *downgraded.XMLID = dsr.XMLID - } else if dsr.Original != nil { + } else if dsr.Original != nil && dsr.Original.XMLID != nil { downgraded.XMLID = new(string) - *downgraded.XMLID = dsr.Original.XMLID - } else { + *downgraded.XMLID = *dsr.Original.XMLID + } else if dsr.Requested.XMLID != nil { downgraded.XMLID = new(string) - *downgraded.XMLID = dsr.Requested.XMLID + *downgraded.XMLID = *dsr.Requested.XMLID } return downgraded } @@ -870,13 +870,13 @@ func (dsr *DeliveryServiceRequestV40) SetXMLID() { return } - if dsr.ChangeType == DSRChangeTypeDelete && dsr.Original != nil { - dsr.XMLID = dsr.Original.XMLID + if dsr.ChangeType == DSRChangeTypeDelete && dsr.Original != nil && dsr.Original.XMLID != nil { + dsr.XMLID = *dsr.Original.XMLID return } - if dsr.Requested != nil { - dsr.XMLID = dsr.Requested.XMLID + if dsr.Requested != nil && dsr.Requested.XMLID != nil { + dsr.XMLID = *dsr.Requested.XMLID } } diff --git a/lib/go-tc/deliveryservice_requests_test.go b/lib/go-tc/deliveryservice_requests_test.go index 2441439074..2a6b00d07f 100644 --- a/lib/go-tc/deliveryservice_requests_test.go +++ b/lib/go-tc/deliveryservice_requests_test.go @@ -151,7 +151,7 @@ func TestDeliveryServiceRequestV40_Downgrade(t *testing.T) { Requested: &DeliveryServiceV4{}, Status: RequestStatusComplete, } - dsr.Requested.XMLID = xmlid + dsr.Requested.XMLID = &xmlid downgraded := dsr.Downgrade() if downgraded.Assignee != nil { @@ -214,7 +214,8 @@ func ExampleDeliveryServiceRequestV40_SetXMLID() { fmt.Println(dsr.XMLID == "") dsr.Requested = new(DeliveryServiceV4) - dsr.Requested.XMLID = "test" + dsr.Requested.XMLID = new(string) + *dsr.Requested.XMLID = "test" dsr.SetXMLID() fmt.Println(dsr.XMLID) diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go index 387704e795..34d2196af1 100644 --- a/lib/go-tc/deliveryservices.go +++ b/lib/go-tc/deliveryservices.go @@ -195,17 +195,17 @@ type DeliveryServiceFieldsV31 struct { // Traffic Ops API. type DeliveryServiceV40 struct { // Active dictates whether the Delivery Service is routed by Traffic Router. - Active bool `json:"active" db:"active"` + Active *bool `json:"active" db:"active"` // AnonymousBlockingEnabled sets whether or not anonymized IP addresses // (e.g. Tor exit nodes) should be restricted from accessing the Delivery // Service's content. - AnonymousBlockingEnabled bool `json:"anonymousBlockingEnabled" db:"anonymous_blocking_enabled"` + AnonymousBlockingEnabled *bool `json:"anonymousBlockingEnabled" db:"anonymous_blocking_enabled"` // CCRDNSTTL sets the Time-to-Live - in seconds - for DNS responses for this // Delivery Service from Traffic Router. CCRDNSTTL *int `json:"ccrDnsTtl" db:"ccr_dns_ttl"` // CDNID is the integral, unique identifier for the CDN to which the // Delivery Service belongs. - CDNID int `json:"cdnId" db:"cdn_id"` + CDNID *int `json:"cdnId" db:"cdn_id"` // CDNName is the name of the CDN to which the Delivery Service belongs. CDNName *string `json:"cdnName"` // CheckPath is a path which may be requested of the Delivery Service's @@ -222,10 +222,10 @@ type DeliveryServiceV40 struct { // DeepCachingType may only legally point to 'ALWAYS' or 'NEVER', which // define whether "deep caching" may or may not be used for this Delivery // Service, respectively. - DeepCachingType DeepCachingType `json:"deepCachingType" db:"deep_caching_type"` + DeepCachingType *DeepCachingType `json:"deepCachingType" db:"deep_caching_type"` // DisplayName is a human-friendly name that might be used in some UIs // somewhere. - DisplayName string `json:"displayName" db:"display_name"` + DisplayName *string `json:"displayName" db:"display_name"` // DNSBypassCNAME is a fully qualified domain name to be used in a CNAME // record presented to clients in bypass scenarios. DNSBypassCNAME *string `json:"dnsBypassCname" db:"dns_bypass_cname"` @@ -242,7 +242,7 @@ type DeliveryServiceV40 struct { // transferred between clients, origins, and cache servers when obtaining // and serving content for this Delivery Service. // See Also: https://en.wikipedia.org/wiki/Differentiated_services - DSCP int `json:"dscp" db:"dscp"` + DSCP *int `json:"dscp" db:"dscp"` // EcsEnabled describes whether or not the Traffic Router's EDNS0 Client // Subnet extensions should be enabled when serving DNS responses for this // Delivery Service. Even if this is true, the Traffic Router may still @@ -273,7 +273,7 @@ type DeliveryServiceV40 struct { // 2 (which indicates that content should be served to clients whose IP // addresses can be found within a Coverage Zone File OR are allowed access // according to the "array" in GeoLimitCountries). - GeoLimit int `json:"geoLimit" db:"geo_limit"` + GeoLimit *int `json:"geoLimit" db:"geo_limit"` // GeoLimitCountries is an "array" of "country codes" that itemizes the // countries within which the Delivery Service's content ought to be made // available. This has no effect if GeoLimit is not a pointer to exactly the @@ -287,7 +287,7 @@ type DeliveryServiceV40 struct { // only valid values to which it may point are 0 (which indicates the use of // a MaxMind GeoIP2 database) and 1 (which indicates the use of a Neustar // GeoPoint IP address database). - GeoProvider int `json:"geoProvider" db:"geo_provider"` + GeoProvider *int `json:"geoProvider" db:"geo_provider"` // GlobalMaxMBPS defines a maximum number of MegaBytes Per Second which may // be served for the Delivery Service before redirecting clients to bypass // locations. @@ -316,7 +316,7 @@ type DeliveryServiceV40 struct { InnerHeaderRewrite *string `json:"innerHeaderRewrite" db:"inner_header_rewrite"` // IPV6RoutingEnabled controls whether or not routing over IPv6 should be // done for this Delivery Service. - IPV6RoutingEnabled bool `json:"ipv6RoutingEnabled" db:"ipv6_routing_enabled"` + IPV6RoutingEnabled *bool `json:"ipv6RoutingEnabled" db:"ipv6_routing_enabled"` // LastHeaderRewrite is a "header rewrite rule" used by ATS at the first // caching layer encountered in the Delivery Service's Topology, or nil if // there is no such rule. This has no effect on Delivery Services that don't @@ -326,7 +326,7 @@ type DeliveryServiceV40 struct { // updated. LastUpdated time.Time `json:"lastUpdated" db:"last_updated"` // LogsEnabled controls nothing. It is kept only for legacy compatibility. - LogsEnabled bool `json:"logsEnabled" db:"logs_enabled"` + LogsEnabled *bool `json:"logsEnabled" db:"logs_enabled"` // LongDesc is a description of the Delivery Service, having arbitrary // length. LongDesc *string `json:"longDesc" db:"long_desc"` @@ -419,7 +419,7 @@ type DeliveryServiceV40 struct { // rules are configured on the Traffic Router serving content for this // Delivery Service will have an effect on the traffic of this Delivery // Service. - RegionalGeoBlocking bool `json:"regionalGeoBlocking" db:"regional_geo_blocking"` + RegionalGeoBlocking *bool `json:"regionalGeoBlocking" db:"regional_geo_blocking"` // RemapText is raw text to insert in "remap.config" on the cache servers // serving content for this Delivery Service. Care is necessitated in its // use, because the input is in no way restricted, validated, or limited in @@ -428,7 +428,7 @@ type DeliveryServiceV40 struct { // RoutingName defines the lowest-level DNS label used by the Delivery // Service, e.g. if trafficcontrol.apache.org were a Delivery Service, it // would have a RoutingName of "trafficcontrol". - RoutingName string `json:"routingName" db:"routing_name"` + RoutingName *string `json:"routingName" db:"routing_name"` // ServiceCategory defines a category to which a Delivery Service may // belong, which will cause HTTP Responses containing content for the // Delivery Service to have the "X-CDN-SVC" header with a value that is the @@ -449,7 +449,7 @@ type DeliveryServiceV40 struct { Tenant *string `json:"tenant"` // TenantID is the integral, unique identifier for the Tenant to which the // Delivery Service belongs. - TenantID int `json:"tenantId" db:"tenant_id"` + TenantID *int `json:"tenantId" db:"tenant_id"` // TLSVersions is the list of explicitly supported TLS versions for cache // servers serving the Delivery Service's content. TLSVersions []string `json:"tlsVersions" db:"tls_versions"` @@ -472,12 +472,12 @@ type DeliveryServiceV40 struct { Type *DSType `json:"type"` // TypeID is an integral, unique identifier for the Tenant to which the // Delivery Service belongs. - TypeID int `json:"typeId" db:"type"` + TypeID *int `json:"typeId" db:"type"` // XMLID is a unique identifier that is also the second lowest-level DNS // label used by the Delivery Service. For example, if a Delivery Service's // content may be requested from video.demo1.mycdn.ciab.test, it may be // inferred that the Delivery Service's XMLID is demo1. - XMLID string `json:"xmlId" db:"xml_id"` + XMLID *string `json:"xmlId" db:"xml_id"` } // DeliveryServiceV4 is a Delivery Service as it appears in version 4 of the @@ -750,40 +750,32 @@ func (ds *DeliveryServiceV4) RemoveLD1AndLD2() DeliveryServiceV4 { // DowngradeToV3 converts the 4.x DS to a 3.x DS. func (ds *DeliveryServiceV4) DowngradeToV3() DeliveryServiceNullableV30 { var ret DeliveryServiceNullableV30 - ret.Active = new(bool) - *ret.Active = ds.Active - ret.AnonymousBlockingEnabled = new(bool) - *ret.AnonymousBlockingEnabled = ds.AnonymousBlockingEnabled + ret.Active = ds.Active + ret.AnonymousBlockingEnabled = ds.AnonymousBlockingEnabled ret.CCRDNSTTL = ds.CCRDNSTTL - ret.CDNID = new(int) - *ret.CDNID = ds.CDNID + ret.CDNID = ds.CDNID ret.CDNName = ds.CDNName ret.CheckPath = ds.CheckPath ret.ConsistentHashRegex = ds.ConsistentHashRegex ret.ConsistentHashQueryParams = make([]string, len(ds.ConsistentHashQueryParams)) copy(ret.ConsistentHashQueryParams, ds.ConsistentHashQueryParams) - ret.DeepCachingType = new(DeepCachingType) - *ret.DeepCachingType = ds.DeepCachingType - ret.DisplayName = new(string) - *ret.DisplayName = ds.DisplayName + ret.DeepCachingType = ds.DeepCachingType + ret.DisplayName = ds.DisplayName ret.DNSBypassCNAME = ds.DNSBypassCNAME ret.DNSBypassIP = ds.DNSBypassIP ret.DNSBypassIP6 = ds.DNSBypassIP6 ret.DNSBypassTTL = ds.DNSBypassTTL - ret.DSCP = new(int) - *ret.DSCP = ds.DSCP + ret.DSCP = ds.DSCP ret.EcsEnabled = ds.EcsEnabled ret.EdgeHeaderRewrite = ds.EdgeHeaderRewrite ret.ExampleURLs = make([]string, len(ds.ExampleURLs)) copy(ret.ExampleURLs, ds.ExampleURLs) ret.FirstHeaderRewrite = ds.FirstHeaderRewrite ret.FQPacingRate = ds.FQPacingRate - ret.GeoLimit = new(int) - *ret.GeoLimit = ds.GeoLimit + ret.GeoLimit = ds.GeoLimit ret.GeoLimitCountries = ds.GeoLimitCountries ret.GeoLimitRedirectURL = ds.GeoLimitRedirectURL - ret.GeoProvider = new(int) - *ret.GeoProvider = ds.GeoProvider + ret.GeoProvider = ds.GeoProvider ret.GlobalMaxMBPS = ds.GlobalMaxMBPS ret.GlobalMaxTPS = ds.GlobalMaxTPS ret.HTTPBypassFQDN = ds.HTTPBypassFQDN @@ -791,12 +783,10 @@ func (ds *DeliveryServiceV4) DowngradeToV3() DeliveryServiceNullableV30 { ret.InfoURL = ds.InfoURL ret.InitialDispersion = ds.InitialDispersion ret.InnerHeaderRewrite = ds.InnerHeaderRewrite - ret.IPV6RoutingEnabled = new(bool) - *ret.IPV6RoutingEnabled = ds.IPV6RoutingEnabled + ret.IPV6RoutingEnabled = ds.IPV6RoutingEnabled ret.LastHeaderRewrite = ds.LastHeaderRewrite ret.LastUpdated = TimeNoModFromTime(ds.LastUpdated) - ret.LogsEnabled = new(bool) - *ret.LogsEnabled = ds.LogsEnabled + ret.LogsEnabled = ds.LogsEnabled ret.LongDesc = ds.LongDesc ret.LongDesc1 = ds.LongDesc1 ret.LongDesc2 = ds.LongDesc2 @@ -824,26 +814,21 @@ func (ds *DeliveryServiceV4) DowngradeToV3() DeliveryServiceNullableV30 { ret.RangeRequestHandling = ds.RangeRequestHandling ret.RangeSliceBlockSize = ds.RangeSliceBlockSize ret.RegexRemap = ds.RegexRemap - ret.RegionalGeoBlocking = new(bool) - *ret.RegionalGeoBlocking = ds.RegionalGeoBlocking + ret.RegionalGeoBlocking = ds.RegionalGeoBlocking ret.RemapText = ds.RemapText - ret.RoutingName = new(string) - *ret.RoutingName = ds.RoutingName + ret.RoutingName = ds.RoutingName ret.ServiceCategory = ds.ServiceCategory ret.Signed = ds.Signed ret.SigningAlgorithm = ds.SigningAlgorithm ret.SSLKeyVersion = ds.SSLKeyVersion ret.Tenant = ds.Tenant - ret.TenantID = new(int) - *ret.TenantID = ds.TenantID + ret.TenantID = ds.TenantID ret.Topology = ds.Topology ret.TRResponseHeaders = ds.TRResponseHeaders ret.TRRequestHeaders = ds.TRRequestHeaders ret.Type = ds.Type - ret.TypeID = new(int) - *ret.TypeID = ds.TypeID - ret.XMLID = new(string) - *ret.XMLID = ds.XMLID + ret.TypeID = ds.TypeID + ret.XMLID = ds.XMLID return ret } @@ -851,58 +836,32 @@ func (ds *DeliveryServiceV4) DowngradeToV3() DeliveryServiceNullableV30 { // UpgradeToV4 converts the 3.x DS to a 4.x DS. func (ds *DeliveryServiceNullableV30) UpgradeToV4() DeliveryServiceV4 { var ret DeliveryServiceV4 - if ds.Active != nil && *ds.Active { - ret.Active = true - } else { - ret.Active = false - } - if ds.AnonymousBlockingEnabled != nil && *ds.AnonymousBlockingEnabled { - ret.AnonymousBlockingEnabled = true - } else { - ret.AnonymousBlockingEnabled = false - } + ret.Active = ds.Active + ret.AnonymousBlockingEnabled = ds.AnonymousBlockingEnabled ret.CCRDNSTTL = ds.CCRDNSTTL - if ds.CDNID != nil { - ret.CDNID = *ds.CDNID - } + ret.CDNID = ds.CDNID ret.CDNName = ds.CDNName ret.CheckPath = ds.CheckPath ret.ConsistentHashRegex = ds.ConsistentHashRegex ret.ConsistentHashQueryParams = make([]string, len(ds.ConsistentHashQueryParams)) copy(ret.ConsistentHashQueryParams, ds.ConsistentHashQueryParams) - if ds.DeepCachingType != nil && *ds.DeepCachingType == DeepCachingTypeAlways { - ret.DeepCachingType = DeepCachingTypeAlways - } else { - ret.DeepCachingType = DeepCachingTypeNever - } - if ds.DisplayName != nil { - ret.DisplayName = *ds.DisplayName - } + ret.DeepCachingType = ds.DeepCachingType + ret.DisplayName = ds.DisplayName ret.DNSBypassCNAME = ds.DNSBypassCNAME ret.DNSBypassIP = ds.DNSBypassIP ret.DNSBypassIP6 = ds.DNSBypassIP6 ret.DNSBypassTTL = ds.DNSBypassTTL - if ds.DSCP != nil { - ret.DSCP = *ds.DSCP - } + ret.DSCP = ds.DSCP ret.EcsEnabled = ds.EcsEnabled ret.EdgeHeaderRewrite = ds.EdgeHeaderRewrite ret.ExampleURLs = make([]string, len(ds.ExampleURLs)) copy(ret.ExampleURLs, ds.ExampleURLs) ret.FirstHeaderRewrite = ds.FirstHeaderRewrite ret.FQPacingRate = ds.FQPacingRate - if ds.GeoLimit != nil && (*ds.GeoLimit == 1 || *ds.GeoLimit == 2) { - ret.GeoLimit = *ds.GeoLimit - } else { - ret.GeoLimit = 0 - } + ret.GeoLimit = ds.GeoLimit ret.GeoLimitCountries = ds.GeoLimitCountries ret.GeoLimitRedirectURL = ds.GeoLimitRedirectURL - if ds.GeoProvider != nil && *ds.GeoProvider == 1 { - ret.GeoProvider = 1 - } else { - ret.GeoProvider = 0 - } + ret.GeoProvider = ds.GeoProvider ret.GlobalMaxMBPS = ds.GlobalMaxMBPS ret.GlobalMaxTPS = ds.GlobalMaxTPS ret.HTTPBypassFQDN = ds.HTTPBypassFQDN @@ -910,20 +869,12 @@ func (ds *DeliveryServiceNullableV30) UpgradeToV4() DeliveryServiceV4 { ret.InfoURL = ds.InfoURL ret.InitialDispersion = ds.InitialDispersion ret.InnerHeaderRewrite = ds.InnerHeaderRewrite - if ds.IPV6RoutingEnabled != nil && *ds.IPV6RoutingEnabled { - ret.IPV6RoutingEnabled = true - } else { - ret.IPV6RoutingEnabled = false - } + ret.IPV6RoutingEnabled = ds.IPV6RoutingEnabled ret.LastHeaderRewrite = ds.LastHeaderRewrite if ds.LastUpdated != nil { ret.LastUpdated = ds.LastUpdated.Time } - if ds.LogsEnabled != nil && *ds.LogsEnabled { - ret.LogsEnabled = true - } else { - ret.LogsEnabled = false - } + ret.LogsEnabled = ds.LogsEnabled ret.LongDesc = ds.LongDesc ret.LongDesc1 = ds.LongDesc1 ret.LongDesc2 = ds.LongDesc2 @@ -950,34 +901,22 @@ func (ds *DeliveryServiceNullableV30) UpgradeToV4() DeliveryServiceV4 { ret.RangeRequestHandling = ds.RangeRequestHandling ret.RangeSliceBlockSize = ds.RangeSliceBlockSize ret.RegexRemap = ds.RegexRemap - if ds.RegionalGeoBlocking != nil && *ds.RegionalGeoBlocking { - ret.RegionalGeoBlocking = true - } else { - ret.RegionalGeoBlocking = false - } + ret.RegionalGeoBlocking = ds.RegionalGeoBlocking ret.RemapText = ds.RemapText - if ds.RoutingName != nil { - ret.RoutingName = *ds.RoutingName - } + ret.RoutingName = ds.RoutingName ret.ServiceCategory = ds.ServiceCategory ret.Signed = ds.Signed ret.SigningAlgorithm = ds.SigningAlgorithm ret.SSLKeyVersion = ds.SSLKeyVersion ret.Tenant = ds.Tenant - if ds.TenantID != nil { - ret.TenantID = *ds.TenantID - } + ret.TenantID = ds.TenantID ret.TLSVersions = nil ret.Topology = ds.Topology ret.TRResponseHeaders = ds.TRResponseHeaders ret.TRRequestHeaders = ds.TRRequestHeaders ret.Type = ds.Type - if ds.TypeID != nil { - ret.TypeID = *ds.TypeID - } - if ds.XMLID != nil { - ret.XMLID = *ds.XMLID - } + ret.TypeID = ds.TypeID + ret.XMLID = ds.XMLID return ret } diff --git a/lib/go-tc/deliveryservices_test.go b/lib/go-tc/deliveryservices_test.go index 49ffe4e370..2d32588495 100644 --- a/lib/go-tc/deliveryservices_test.go +++ b/lib/go-tc/deliveryservices_test.go @@ -463,30 +463,30 @@ func dsUpgradeAndDowngradeTestingPair() (DeliveryServiceNullableV30, DeliverySer xmlid := "xmlid" newDS := DeliveryServiceV4{ - Active: false, - AnonymousBlockingEnabled: anonymousBlockingEnabled, + Active: new(bool), + AnonymousBlockingEnabled: &anonymousBlockingEnabled, CCRDNSTTL: &cCRDNSTTL, - CDNID: cdnID, + CDNID: &cdnID, CDNName: &cdnName, CheckPath: &checkPath, ConsistentHashQueryParams: consistentHashQueryParams, ConsistentHashRegex: &consistentHashRegex, - DeepCachingType: deepCachingType, - DisplayName: displayName, + DeepCachingType: &deepCachingType, + DisplayName: &displayName, DNSBypassCNAME: &dnsBypassCNAME, DNSBypassIP: &dnsBypassIP, DNSBypassIP6: &dnsBypassIP6, DNSBypassTTL: &dnsBypassTTL, - DSCP: dscp, + DSCP: &dscp, EcsEnabled: ecsEnabled, EdgeHeaderRewrite: &edgeHeaderRewrite, ExampleURLs: exampleURLs, FirstHeaderRewrite: &firstHeaderRewrite, FQPacingRate: &fqPacingRate, - GeoLimit: geoLimit, + GeoLimit: &geoLimit, GeoLimitCountries: &geoLimitCountries, GeoLimitRedirectURL: &geoLimitRedirectURL, - GeoProvider: geoProvider, + GeoProvider: &geoProvider, GlobalMaxMBPS: &globalMaxMBPS, GlobalMaxTPS: &globalMaxTPS, HTTPBypassFQDN: &hTTPBypassFQDN, @@ -494,10 +494,10 @@ func dsUpgradeAndDowngradeTestingPair() (DeliveryServiceNullableV30, DeliverySer InfoURL: &infoURL, InitialDispersion: &initialDispersion, InnerHeaderRewrite: &innerHeaderRewrite, - IPV6RoutingEnabled: ipv6RoutingEnabled, + IPV6RoutingEnabled: &ipv6RoutingEnabled, LastHeaderRewrite: &lastHeaderRewrite, LastUpdated: lastUpdated.Time, - LogsEnabled: logsEnabled, + LogsEnabled: &logsEnabled, LongDesc: &longDesc, LongDesc1: &longDesc1, LongDesc2: &longDesc2, @@ -519,22 +519,22 @@ func dsUpgradeAndDowngradeTestingPair() (DeliveryServiceNullableV30, DeliverySer RangeRequestHandling: &rangeRequestHandling, RangeSliceBlockSize: &rangeSliceBlockSize, RegexRemap: ®exRemap, - RegionalGeoBlocking: regionalGeoBlocking, + RegionalGeoBlocking: ®ionalGeoBlocking, RemapText: &remapText, - RoutingName: routingName, + RoutingName: &routingName, ServiceCategory: &serviceCategory, Signed: signed, SigningAlgorithm: &signingAlgorithm, SSLKeyVersion: &sSLKeyVersion, Tenant: &tenant, - TenantID: tenantID, + TenantID: &tenantID, TLSVersions: []string{"1.0", "1.1", "1.2", "1.3"}, Topology: &topology, TRResponseHeaders: &trResponseHeaders, TRRequestHeaders: &trRequestHeaders, Type: &typ, - TypeID: typeID, - XMLID: xmlid, + TypeID: &typeID, + XMLID: &xmlid, } active := false diff --git a/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go b/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go index eeb08098ae..2546d92585 100644 --- a/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go +++ b/traffic_ops/testing/api/v4/cachegroupsdeliveryservices_test.go @@ -159,8 +159,12 @@ func setInactive(t *testing.T, dsID int) { } ds := resp.Response[0] - if ds.Active { - ds.Active = false + if ds.Active == nil { + t.Errorf("Deliver Service #%d had null or undefined 'active'", dsID) + ds.Active = new(bool) + } + if *ds.Active { + *ds.Active = false _, _, err = TOSession.UpdateDeliveryService(dsID, ds, client.RequestOptions{}) if err != nil { t.Errorf("Failed to set Delivery Service #%d to inactive: %v", dsID, err) diff --git a/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go b/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go index 92061e9957..dd5c410809 100644 --- a/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go +++ b/traffic_ops/testing/api/v4/deliveryservice_request_comments_test.go @@ -105,22 +105,22 @@ func CreateTestDeliveryServiceRequestComments(t *testing.T) { ds = dsr.Requested } resetDS(ds) - if ds == nil { - t.Fatal("first DSR in the test data had a nil Delivery Service") + if ds == nil || ds.XMLID == nil { + t.Fatal("first DSR in the test data had a nil Delivery Service, or one with no XMLID") } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Fatalf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) + t.Fatalf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) } if len(resp.Response) != 1 { - t.Fatalf("found %d Delivery Service request by XMLID '%s, expected exactly one", len(resp.Response), ds.XMLID) + t.Fatalf("found %d Delivery Service request by XMLID '%s, expected exactly one", len(resp.Response), *ds.XMLID) } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("got Delivery Service Request with xml_id '%s' that had a null ID", ds.XMLID) + t.Fatalf("got Delivery Service Request with xml_id '%s' that had a null ID", *ds.XMLID) } for _, comment := range testData.DeliveryServiceRequestComments { diff --git a/traffic_ops/testing/api/v4/deliveryservice_requests_test.go b/traffic_ops/testing/api/v4/deliveryservice_requests_test.go index 5b072856e2..9f6f60c887 100644 --- a/traffic_ops/testing/api/v4/deliveryservice_requests_test.go +++ b/traffic_ops/testing/api/v4/deliveryservice_requests_test.go @@ -49,11 +49,11 @@ func resetDS(ds *tc.DeliveryServiceV4) { if ds == nil { return } - ds.CDNID = 0 + ds.CDNID = nil ds.ID = nil ds.ProfileID = nil - ds.TenantID = 0 - ds.TypeID = 0 + ds.TenantID = nil + ds.TypeID = nil } func TestDeliveryServiceRequests(t *testing.T) { @@ -147,25 +147,25 @@ func UpdateTestDeliveryServiceRequestsWithHeaders(t *testing.T, header http.Head ds = dsr.Requested } resetDS(ds) - if ds == nil { - t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) + if ds == nil || ds.XMLID == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service, or that Delivery Service had a null or undefined XMLID", dsrGood) } opts := client.NewRequestOptions() opts.Header = header - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) + t.Errorf("cannot get Delivery Service Request by XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) } if len(resp.Response) == 0 { t.Fatal("Length of GET DeliveryServiceRequest is 0") } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("Got a DSR for XML ID '%s' that had a nil ID", ds.XMLID) + t.Fatalf("Got a DSR for XML ID '%s' that had a nil ID", *ds.XMLID) } if respDSR.ChangeType != dsr.ChangeType { - t.Fatalf("remote representation of DSR with XMLID '%s' differed from stored data", ds.XMLID) + t.Fatalf("remote representation of DSR with XMLID '%s' differed from stored data", *ds.XMLID) } var respDS *tc.DeliveryServiceV4 if respDSR.ChangeType == tc.DSRChangeTypeDelete { @@ -174,7 +174,8 @@ func UpdateTestDeliveryServiceRequestsWithHeaders(t *testing.T, header http.Head respDS = respDSR.Requested } - respDS.DisplayName = "new display name" + respDS.DisplayName = new(string) + *respDS.DisplayName = "new display name" opts.QueryParameters.Del("xmlId") _, reqInf, err := TOSession.UpdateDeliveryServiceRequest(*respDSR.ID, respDSR, opts) if err == nil { @@ -200,13 +201,13 @@ func GetTestDeliveryServiceRequestsIMSAfterChange(t *testing.T, header http.Head } resetDS(ds) - if ds == nil { - t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) + if ds == nil || ds.XMLID == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service, or that Delivery Service had a null or undefined XMLID", dsrGood) } opts := client.NewRequestOptions() opts.Header = header - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) resp, reqInf, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { t.Fatalf("Expected no error, but got: %v - alerts: %+v", err, resp.Alerts) @@ -283,9 +284,9 @@ func TestDeliveryServiceRequestRules(t *testing.T) { if ds == nil { t.Fatalf("the %dth DSR in the test data had no DeliveryService", dsrGood) } - ds.DisplayName = displayName - ds.RoutingName = routingName - ds.XMLID = XMLID + ds.DisplayName = &displayName + ds.RoutingName = &routingName + ds.XMLID = &XMLID _, _, err := TOSession.CreateDeliveryServiceRequest(dsr, client.RequestOptions{}) if err == nil { @@ -310,8 +311,8 @@ func TestDeliveryServiceRequestTypeFields(t *testing.T) { ds = dsr.Requested } resetDS(ds) - if ds == nil { - t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrBadTenant) + if ds == nil || ds.XMLID == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service, or that Delivery Service had a null or undefined XMLID", dsrBadTenant) } resp, _, err := TOSession.CreateDeliveryServiceRequest(dsr, client.RequestOptions{}) @@ -334,16 +335,16 @@ func TestDeliveryServiceRequestTypeFields(t *testing.T) { } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) dsrs, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("Unexpected error retriving Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, dsrs.Alerts) + t.Errorf("Unexpected error retriving Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, dsrs.Alerts) } if len(dsrs.Response) != 1 { - t.Fatalf("expected exactly one Deliveryservice Request with XMLID '%s'; got %d", ds.XMLID, len(dsrs.Response)) + t.Fatalf("expected exactly one Deliveryservice Request with XMLID '%s'; got %d", *ds.XMLID, len(dsrs.Response)) } if dsrs.Response[0].ID == nil { - t.Fatalf("got a DSR with a null ID by XMLID '%s'", ds.XMLID) + t.Fatalf("got a DSR with a null ID by XMLID '%s'", *ds.XMLID) } alert, _, err := TOSession.DeleteDeliveryServiceRequest(*dsrs.Response[0].ID, client.RequestOptions{}) @@ -520,14 +521,14 @@ func GetTestDeliveryServiceRequestsIMS(t *testing.T) { ds = dsr.Requested } resetDS(ds) - if ds == nil { - t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) + if ds == nil || ds.XMLID == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service, or that Delivery Service had null or undefined XMLID", dsrGood) } - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) resp, reqInf, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Fatalf("Unexpected error getting Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) + t.Fatalf("Unexpected error getting Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) } if reqInf.StatusCode != http.StatusNotModified { t.Fatalf("Expected 304 status code, got %v", reqInf.StatusCode) @@ -549,15 +550,15 @@ func GetTestDeliveryServiceRequests(t *testing.T) { } resetDS(ds) - if ds == nil { - t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) + if ds == nil || ds.XMLID == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service, or that Delivery Service had a null or undefined XMLID", dsrGood) } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) + t.Errorf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) } } @@ -578,22 +579,22 @@ func UpdateTestDeliveryServiceRequests(t *testing.T) { } resetDS(ds) - if ds == nil { - t.Fatalf("the %dth DSR in the test data had no Delivery Service", dsrGood) + if ds == nil || ds.XMLID == nil { + t.Fatalf("the %dth DSR in the test data had no Delivery Service, or that Delivery Service had a null or undefined XMLID", dsrGood) } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Errorf("cannot get Delivery Service Request with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) + t.Errorf("cannot get Delivery Service Request with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Deliver Service Request to exist with XMLID '%s', but none were found in Traffic Ops", ds.XMLID) + t.Fatalf("Expected at least one Deliver Service Request to exist with XMLID '%s', but none were found in Traffic Ops", *ds.XMLID) } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("got a DSR by XMLID '%s' with a null or undefined ID", ds.XMLID) + t.Fatalf("got a DSR by XMLID '%s' with a null or undefined ID", *ds.XMLID) } var respDS *tc.DeliveryServiceV4 if dsr.ChangeType == tc.DSRChangeTypeDelete { @@ -602,7 +603,7 @@ func UpdateTestDeliveryServiceRequests(t *testing.T) { respDS = dsr.Requested } expDisplayName := "new display name" - respDS.DisplayName = expDisplayName + respDS.DisplayName = &expDisplayName id := *respDSR.ID alerts, _, err := TOSession.UpdateDeliveryServiceRequest(id, respDSR, client.RequestOptions{}) if err != nil { @@ -628,11 +629,11 @@ func UpdateTestDeliveryServiceRequests(t *testing.T) { respDS = dsr.Requested } - if respDS == nil { - t.Fatalf("Got DSR by ID '%d' that had no Delivery Service", id) + if respDS == nil || respDS.DisplayName == nil { + t.Fatalf("Got DSR by ID '%d' that had no DeliveryService - or said DeliveryService had no DisplayName", id) } - if respDS.DisplayName != expDisplayName { - t.Errorf("results do not match actual: %s, expected: %s", respDS.DisplayName, expDisplayName) + if *respDS.DisplayName != expDisplayName { + t.Errorf("results do not match actual: %s, expected: %s", *respDS.DisplayName, expDisplayName) } } @@ -653,22 +654,22 @@ func DeleteTestDeliveryServiceRequests(t *testing.T) { } resetDS(ds) - if ds == nil { + if ds == nil || ds.XMLID == nil { t.Fatalf("the %dth DSR in the test data had no DeliveryService - or that DeliveryService had no XMLID", dsrGood) } opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", ds.XMLID) + opts.QueryParameters.Set("xmlId", *ds.XMLID) resp, _, err := TOSession.GetDeliveryServiceRequests(opts) if err != nil { - t.Fatalf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) + t.Fatalf("cannot get Delivery Service Requests with XMLID '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) } if len(resp.Response) < 1 { - t.Fatalf("expected at least one Delivery Service Request to have XMLID '%s', got none", ds.XMLID) + t.Fatalf("expected at least one Delivery Service Request to have XMLID '%s', got none", *ds.XMLID) } respDSR := resp.Response[0] if respDSR.ID == nil { - t.Fatalf("Got a DSR by XMLID '%s' that had no ID", ds.XMLID) + t.Fatalf("Got a DSR by XMLID '%s' that had no ID", *ds.XMLID) } alert, _, err := TOSession.DeleteDeliveryServiceRequest(*respDSR.ID, client.RequestOptions{}) if err != nil { diff --git a/traffic_ops/testing/api/v4/deliveryservices_test.go b/traffic_ops/testing/api/v4/deliveryservices_test.go index 21064b6b9f..3fbf21931d 100644 --- a/traffic_ops/testing/api/v4/deliveryservices_test.go +++ b/traffic_ops/testing/api/v4/deliveryservices_test.go @@ -195,6 +195,9 @@ func UpdateTestDeliveryServicesWithHeaders(t *testing.T, header http.Header) { t.Fatal("Need at least one Delivery Service to test updating Delivery Services with HTTP Headers") } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with null or undefined XMLID") + } opts := client.RequestOptions{Header: header} dses, _, err := TOSession.GetDeliveryServices(opts) @@ -205,17 +208,17 @@ func UpdateTestDeliveryServicesWithHeaders(t *testing.T, header http.Header) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.XMLID == firstDS.XMLID { + if ds.XMLID != nil && *ds.XMLID == *firstDS.XMLID { found = true remoteDS = ds break } } if !found { - t.Fatalf("GET Delivery Services missing: %v", firstDS.XMLID) + t.Fatalf("GET Delivery Services missing: %s", *firstDS.XMLID) } if remoteDS.ID == nil { - t.Fatalf("Traffic Ops returned a representation for Delivery Service '%s' that had a null or undefined ID", firstDS.XMLID) + t.Fatalf("Traffic Ops returned a representation for Delivery Service '%s' that had a null or undefined ID", *firstDS.XMLID) } updatedLongDesc := "something different" @@ -270,11 +273,11 @@ func createBlankCDN(cdnName string, t *testing.T) tc.CDN { } func cleanUp(t *testing.T, ds tc.DeliveryServiceV4, oldCDNID int, newCDNID int, sslKeyVersions []string) { - xmlid := ds.XMLID - if ds.ID == nil { - t.Error("Cannot clean up Delivery Service with nil ID") + if ds.ID == nil || ds.XMLID == nil { + t.Error("Cannot clean up Delivery Service with nil ID and/or XMLID") return } + xmlid := *ds.XMLID id := *ds.ID opts := client.NewRequestOptions() @@ -328,18 +331,19 @@ func cleanUp(t *testing.T, ds tc.DeliveryServiceV4, oldCDNID int, newCDNID int, // XMLID // // BUT, will ALWAYS have nil MaxRequestHeaderBytes. +// Note that the Tenant is hard-coded to #1. func getCustomDS(cdnID, typeID int, displayName, routingName, orgFQDN, dsID string) tc.DeliveryServiceV4 { customDS := tc.DeliveryServiceV4{} - customDS.Active = true - customDS.CDNID = cdnID - customDS.DSCP = 0 - customDS.DisplayName = displayName - customDS.RoutingName = routingName - customDS.GeoLimit = 0 - customDS.GeoProvider = 0 - customDS.IPV6RoutingEnabled = false + customDS.Active = util.BoolPtr(true) + customDS.CDNID = util.IntPtr(cdnID) + customDS.DSCP = util.IntPtr(0) + customDS.DisplayName = util.StrPtr(displayName) + customDS.RoutingName = util.StrPtr(routingName) + customDS.GeoLimit = util.IntPtr(0) + customDS.GeoProvider = util.IntPtr(0) + customDS.IPV6RoutingEnabled = util.BoolPtr(false) customDS.InitialDispersion = util.IntPtr(1) - customDS.LogsEnabled = true + customDS.LogsEnabled = util.BoolPtr(true) customDS.MissLat = util.FloatPtr(0) customDS.MissLong = util.FloatPtr(0) customDS.MultiSiteOrigin = util.BoolPtr(false) @@ -347,10 +351,10 @@ func getCustomDS(cdnID, typeID int, displayName, routingName, orgFQDN, dsID stri customDS.Protocol = util.IntPtr(2) customDS.QStringIgnore = util.IntPtr(0) customDS.RangeRequestHandling = util.IntPtr(0) - customDS.RegionalGeoBlocking = false - customDS.TenantID = 1 - customDS.TypeID = typeID - customDS.XMLID = dsID + customDS.RegionalGeoBlocking = util.BoolPtr(false) + customDS.TenantID = util.IntPtr(1) + customDS.TypeID = util.IntPtr(typeID) + customDS.XMLID = util.StrPtr(dsID) customDS.MaxRequestHeaderBytes = nil return customDS } @@ -379,6 +383,9 @@ func DeleteCDNOldSSLKeys(t *testing.T) { t.Fatalf("Expected Delivery Service creation to return exactly one Delivery Service, got: %d", len(resp.Response)) } ds := resp.Response[0] + if ds.XMLID == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID") + } ds.CDNName = &cdn.Name sslKeyRequestFields := tc.SSLKeyRequestFields{ @@ -389,9 +396,9 @@ func DeleteCDNOldSSLKeys(t *testing.T) { Country: util.StrPtr("CO"), State: util.StrPtr("ST"), } - genResp, _, err := TOSession.GenerateSSLKeysForDS(ds.XMLID, *ds.CDNName, sslKeyRequestFields, client.RequestOptions{}) + genResp, _, err := TOSession.GenerateSSLKeysForDS(*ds.XMLID, *ds.CDNName, sslKeyRequestFields, client.RequestOptions{}) if err != nil { - t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", ds.XMLID, err, genResp.Alerts) + t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", *ds.XMLID, err, genResp.Alerts) } defer cleanUp(t, ds, cdn.ID, -1, []string{"1"}) @@ -406,15 +413,15 @@ func DeleteCDNOldSSLKeys(t *testing.T) { t.Fatalf("Expected Delivery Service creation to return exactly one Delivery Service, got: %d", len(resp.Response)) } ds2 := resp.Response[0] - if ds2.ID == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") + if ds2.XMLID == nil || ds2.ID == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID and/or ID") } ds2.CDNName = &cdn.Name sslKeyRequestFields.HostName = util.StrPtr("*.test2.com") - genResp, _, err = TOSession.GenerateSSLKeysForDS(ds2.XMLID, *ds2.CDNName, sslKeyRequestFields, client.RequestOptions{}) + genResp, _, err = TOSession.GenerateSSLKeysForDS(*ds2.XMLID, *ds2.CDNName, sslKeyRequestFields, client.RequestOptions{}) if err != nil { - t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", ds2.XMLID, err, genResp.Alerts) + t.Fatalf("Unexpected error generaing SSL Keys for Delivery Service '%s': %v - alerts: %+v", *ds2.XMLID, err, genResp.Alerts) } var cdnKeys []tc.CDNSSLKeys @@ -491,9 +498,12 @@ func DeliveryServiceSSLKeys(t *testing.T) { t.Fatalf("Expected Delivery Service creation to return exactly one Delivery Service, got: %d", len(resp.Response)) } ds := resp.Response[0] + if ds.XMLID == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID") + } ds.CDNName = &cdn.Name - genResp, _, err := TOSession.GenerateSSLKeysForDS(ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ + genResp, _, err := TOSession.GenerateSSLKeysForDS(*ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ BusinessUnit: util.StrPtr("BU"), City: util.StrPtr("CI"), Organization: util.StrPtr("OR"), @@ -502,7 +512,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { State: util.StrPtr("ST"), }, client.RequestOptions{}) if err != nil { - t.Fatalf("Unexpected error generating SSL Keys for Delivery Service '%s': %v - alerts: %+v", ds.XMLID, err, genResp.Alerts) + t.Fatalf("Unexpected error generating SSL Keys for Delivery Service '%s': %v - alerts: %+v", *ds.XMLID, err, genResp.Alerts) } defer cleanUp(t, ds, cdn.ID, -1, []string{"1"}) @@ -510,7 +520,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { for tries := 0; tries < 5; tries++ { time.Sleep(time.Second) var sslKeysResp tc.DeliveryServiceSSLKeysResponse - sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(ds.XMLID, client.RequestOptions{}) + sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(*ds.XMLID, client.RequestOptions{}) *dsSSLKey = sslKeysResp.Response if err == nil && dsSSLKey != nil { break @@ -518,7 +528,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { } if err != nil || dsSSLKey == nil { - t.Fatalf("unable to get DS %v SSL key: %v", ds.XMLID, err) + t.Fatalf("unable to get DS %s SSL key: %v", *ds.XMLID, err) } if dsSSLKey.Certificate.Key == "" { t.Errorf("expected a valid key but got nothing") @@ -558,7 +568,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { for tries := 0; tries < 5; tries++ { time.Sleep(time.Second) var sslKeysResp tc.DeliveryServiceSSLKeysResponse - sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(ds.XMLID, client.RequestOptions{}) + sslKeysResp, _, err = TOSession.GetDeliveryServiceSSLKeys(*ds.XMLID, client.RequestOptions{}) *dsSSLKey = sslKeysResp.Response if err == nil && dsSSLKey != nil { break @@ -566,7 +576,7 @@ func DeliveryServiceSSLKeys(t *testing.T) { } if err != nil || dsSSLKey == nil { - t.Fatalf("unable to get DS %v SSL key: %v", ds.XMLID, err) + t.Fatalf("unable to get DS %s SSL key: %v", *ds.XMLID, err) } if dsSSLKey.Certificate.Key == "" { t.Errorf("expected a valid key but got nothing") @@ -605,14 +615,14 @@ func SSLDeliveryServiceCDNUpdateTest(t *testing.T) { t.Fatalf("Expected Delivery Service creation to create exactly one Delivery Service, Traffic Ops indicates %d were created", len(resp.Response)) } ds := resp.Response[0] - if ds.ID == nil { - t.Fatal("Traffic Ops created a Delivery Service with no ID") + if ds.ID == nil || ds.XMLID == nil { + t.Fatal("Traffic Ops created a Delivery Service with null or undefined XMLID and/or ID") } ds.CDNName = &oldCdn.Name defer cleanUp(t, ds, oldCdn.ID, newCdn.ID, []string{"1"}) - _, _, err = TOSession.GenerateSSLKeysForDS(ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ + _, _, err = TOSession.GenerateSSLKeysForDS(*ds.XMLID, *ds.CDNName, tc.SSLKeyRequestFields{ BusinessUnit: util.StrPtr("BU"), City: util.StrPtr("CI"), Organization: util.StrPtr("OR"), @@ -645,14 +655,14 @@ func SSLDeliveryServiceCDNUpdateTest(t *testing.T) { t.Fatalf("unable to get cdn %v keys: %v", newCdn.Name, err) } - ds.RoutingName = "anothername" + ds.RoutingName = util.StrPtr("anothername") _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err == nil { t.Fatal("should not be able to update delivery service (routing name) as it has ssl keys") } - ds.RoutingName = "routingName" + ds.RoutingName = util.StrPtr("routingName") - ds.CDNID = newCdn.ID + ds.CDNID = &newCdn.ID ds.CDNName = &newCdn.Name _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err == nil { @@ -713,15 +723,24 @@ func PostDeliveryServiceTest(t *testing.T) { t.Fatal("Need at least one testing Delivery Service to test creating Delivery Services") } ds := testData.DeliveryServices[0] - xmlid := ds.XMLID + "-topology-test" + if ds.XMLID == nil { + t.Fatal("Found Delivery Service in testing data with null or undefined XMLID") + } + xmlid := *ds.XMLID + "-topology-test" + ds.XMLID = new(string) _, _, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) if err == nil { t.Error("Expected error with empty xmlid") } + ds.XMLID = nil + _, _, err = TOSession.CreateDeliveryService(ds, client.RequestOptions{}) + if err == nil { + t.Error("Expected error with nil xmlid") + } ds.Topology = new(string) - ds.XMLID = xmlid + ds.XMLID = &xmlid _, reqInf, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) if err == nil { @@ -744,9 +763,13 @@ func CreateTestDeliveryServices(t *testing.T) { } for _, ds := range testData.DeliveryServices { ds = ds.RemoveLD1AndLD2() + if ds.XMLID == nil { + t.Error("Found a Delivery Service in testing data with null or undefined XMLID") + continue + } resp, _, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) if err != nil { - t.Errorf("could not create Delivery Service '%s': %v - alerts: %+v", ds.XMLID, err, resp.Alerts) + t.Errorf("could not create Delivery Service '%s': %v - alerts: %+v", *ds.XMLID, err, resp.Alerts) } } } @@ -778,17 +801,25 @@ func GetTestDeliveryServices(t *testing.T) { } actualDSMap := make(map[string]tc.DeliveryServiceV4, len(actualDSes.Response)) for _, ds := range actualDSes.Response { - actualDSMap[ds.XMLID] = ds + if ds.XMLID == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service with null or undefined XMLID") + continue + } + actualDSMap[*ds.XMLID] = ds } cnt := 0 for _, ds := range testData.DeliveryServices { - if _, ok := actualDSMap[ds.XMLID]; !ok { - t.Errorf("GET DeliveryService missing: %s", ds.XMLID) + if ds.XMLID == nil { + t.Error("Delivery Service found in test data with null or undefined XMLID") + continue + } + if _, ok := actualDSMap[*ds.XMLID]; !ok { + t.Errorf("GET DeliveryService missing: %s", *ds.XMLID) } // exactly one ds should have exactly 3 query params. the rest should have none if c := len(ds.ConsistentHashQueryParams); c > 0 { if c != 3 { - t.Errorf("deliveryservice %s has %d query params; expected 3 or 0", ds.XMLID, c) + t.Errorf("deliveryservice %s has %d query params; expected 3 or 0", *ds.XMLID, c) } cnt++ } @@ -806,7 +837,11 @@ func GetInactiveTestDeliveryServices(t *testing.T) { t.Errorf("cannot get inactive Delivery Services: %v - alerts: %+v", err, inactiveDSes.Alerts) } for _, ds := range inactiveDSes.Response { - if ds.Active { + if ds.Active == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined 'active'") + continue + } + if *ds.Active != false { t.Errorf("expected all delivery services to be inactive, but got atleast one active DS") } } @@ -817,7 +852,11 @@ func GetInactiveTestDeliveryServices(t *testing.T) { t.Errorf("cannot get active Delivery Services: %v - alerts: %+v", err, activeDSes.Alerts) } for _, ds := range activeDSes.Response { - if !ds.Active { + if ds.Active == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined 'active'") + continue + } + if *ds.Active != true { t.Errorf("expected all delivery services to be active, but got atleast one inactive DS") } } @@ -830,14 +869,14 @@ func GetTestDeliveryServicesCapacity(t *testing.T) { } actualDSMap := map[string]tc.DeliveryServiceV4{} for _, ds := range actualDSes.Response { - if ds.ID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") + if ds.ID == nil || ds.XMLID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID and/or ID") continue } - actualDSMap[ds.XMLID] = ds + actualDSMap[*ds.XMLID] = ds capDS, _, err := TOSession.GetDeliveryServiceCapacity(*ds.ID, client.RequestOptions{}) if err != nil { - t.Errorf(`cannot get Delivery Service "%s"'s (#%d) Capacity: %v - alerts: %+v`, ds.XMLID, *ds.ID, err, capDS.Alerts) + t.Errorf(`cannot get Delivery Service "%s"'s (#%d) Capacity: %v - alerts: %+v`, *ds.XMLID, *ds.ID, err, capDS.Alerts) } } @@ -848,6 +887,9 @@ func UpdateTestDeliveryServices(t *testing.T) { t.Fatal("Need at least one Delivery Service to test updating a Delivery Service") } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in the test data with a null or undefined XMLID") + } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) if err != nil { @@ -857,7 +899,11 @@ func UpdateTestDeliveryServices(t *testing.T) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.XMLID == firstDS.XMLID { + if ds.XMLID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID") + continue + } + if *ds.XMLID == *firstDS.XMLID { found = true remoteDS = ds break @@ -925,6 +971,9 @@ func UpdateNullableTestDeliveryServices(t *testing.T) { t.Fatal("Need at least one Delivery Service to test updating nullable fields of a Delivery Service") } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in the test data with a null or undefined XMLID") + } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) if err != nil { @@ -934,11 +983,11 @@ func UpdateNullableTestDeliveryServices(t *testing.T) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.ID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") + if ds.XMLID == nil || ds.ID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID and/or ID") continue } - if ds.XMLID == firstDS.XMLID { + if *ds.XMLID == *firstDS.XMLID { found = true remoteDS = ds break @@ -1031,8 +1080,8 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { t.Fatalf("expected: 1 DS, actual: %d", len(dses.Response)) } ds := dses.Response[0] - if ds.Topology == nil || ds.ID == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined Topology and/or ID") + if ds.Topology == nil || ds.ID == nil || ds.XMLID == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined Topology and/or XMLID and/or ID") } // unassign its topology, add a required capability that its topology // can't satisfy, then attempt to reassign its topology @@ -1048,7 +1097,7 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { } dsrcResp, _, err := TOSession.CreateDeliveryServicesRequiredCapability(reqCap, client.RequestOptions{}) if err != nil { - t.Fatalf("adding 'asdf' required capability to '%s', expected: no error, actual: %v - alerts: %+v", ds.XMLID, err, dsrcResp.Alerts) + t.Fatalf("adding 'asdf' required capability to '%s', expected: no error, actual: %v - alerts: %+v", *ds.XMLID, err, dsrcResp.Alerts) } ds.Topology = &top _, reqInf, err := TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) @@ -1060,7 +1109,7 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { } dsrcResp, _, err = TOSession.DeleteDeliveryServicesRequiredCapability(*ds.ID, "asdf", client.RequestOptions{}) if err != nil { - t.Fatalf("removing 'asdf' required capability from '%s', expected: no error, actual: %v - alerts: %+v", ds.XMLID, err, dsrcResp.Alerts) + t.Fatalf("removing 'asdf' required capability from '%s', expected: no error, actual: %v - alerts: %+v", *ds.XMLID, err, dsrcResp.Alerts) } _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err != nil { @@ -1090,6 +1139,9 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { t.Fatalf("Expected exactly one Delivery Service to have ID %d, found: %d", *ds.ID, len(resp.Response)) } ds = resp.Response[0] + if ds.CDNID == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined CDN ID") + } const cdn1Name = "cdn1" opts = client.NewRequestOptions() @@ -1119,7 +1171,7 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { if cachegroup.ID == nil { t.Fatalf("Traffic Ops returned a representation for Cache Group '%s' that had null or undefined ID", cacheGroupName) } - opts.QueryParameters = url.Values{"cdn": {strconv.Itoa(ds.CDNID)}, "cachegroup": {strconv.Itoa(*cachegroup.ID)}} + opts.QueryParameters = url.Values{"cdn": {strconv.Itoa(*ds.CDNID)}, "cachegroup": {strconv.Itoa(*cachegroup.ID)}} servers, _, err := TOSession.GetServers(opts) if err != nil { t.Fatalf("getting Server with params %v: %v - alerts: %+v", opts.QueryParameters, err, servers.Alerts) @@ -1174,12 +1226,12 @@ func UpdateDeliveryServiceWithInvalidTopology(t *testing.T) { ds.Topology = dsTopology _, reqInf, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err == nil { - t.Fatalf("expected 400-level error assigning Topology %s to Delivery Service %s because Cache Group %s has no Servers in it in CDN %d, no error received", *dsTopology, xmlID, cacheGroupName, ds.CDNID) + t.Fatalf("expected 400-level error assigning Topology %s to Delivery Service %s because Cache Group %s has no Servers in it in CDN %d, no error received", *dsTopology, xmlID, cacheGroupName, *ds.CDNID) } if reqInf.StatusCode < http.StatusBadRequest || reqInf.StatusCode >= http.StatusInternalServerError { t.Fatalf("expected %d-level status code but received status code %d", http.StatusBadRequest, reqInf.StatusCode) } - *server.CDNID = ds.CDNID + *server.CDNID = *ds.CDNID *server.ProfileID = profileCopy.ExistingID // Put things back the way they were @@ -1249,6 +1301,9 @@ func UpdateDeliveryServiceWithInvalidRemapText(t *testing.T) { t.Fatal("Need at least one Delivery Service to test updating Delivery Service with invalid remap text") } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in the test data that has null or undefined XMLID") + } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) if err != nil { @@ -1258,18 +1313,18 @@ func UpdateDeliveryServiceWithInvalidRemapText(t *testing.T) { var remoteDS tc.DeliveryServiceV4 found := false for _, ds := range dses.Response { - if ds.ID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined ID") + if ds.XMLID == nil || ds.ID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined XMLID and/or ID") continue } - if ds.XMLID == firstDS.XMLID { + if *ds.XMLID == *firstDS.XMLID { found = true remoteDS = ds break } } if !found { - t.Fatalf("GET Delivery Services missing: %s", firstDS.XMLID) + t.Fatalf("GET Delivery Services missing: %s", *firstDS.XMLID) } updatedRemapText := "@plugin=tslua.so @pparam=/opt/trafficserver/etc/trafficserver/remapPlugin1.lua\nline2" @@ -1283,8 +1338,7 @@ func UpdateDeliveryServiceWithInvalidRemapText(t *testing.T) { // UpdateDeliveryServiceWithInvalidSliceRangeRequest ensures that a delivery service can't be updated with a invalid slice range request handler setting. func UpdateDeliveryServiceWithInvalidSliceRangeRequest(t *testing.T) { // GET a HTTP / DNS type DS - var dsXML string - found := false + var dsXML *string for _, ds := range testData.DeliveryServices { if ds.Type == nil { t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined Type") @@ -1292,11 +1346,10 @@ func UpdateDeliveryServiceWithInvalidSliceRangeRequest(t *testing.T) { } if ds.Type.IsDNS() || ds.Type.IsHTTP() { dsXML = ds.XMLID - found = true break } } - if !found { + if dsXML == nil { t.Fatal("no HTTP or DNS Delivery Services to test with") } @@ -1306,20 +1359,20 @@ func UpdateDeliveryServiceWithInvalidSliceRangeRequest(t *testing.T) { } var remoteDS tc.DeliveryServiceV4 - found = false + found := false for _, ds := range dses.Response { - if ds.ID == nil { - t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined ID") + if ds.XMLID == nil || ds.ID == nil { + t.Error("Traffic Ops returned a representation for a Delivery Service that had null or undefined XMLID and/or ID") continue } - if ds.XMLID == dsXML { + if *ds.XMLID == *dsXML { found = true remoteDS = ds break } } if !found { - t.Fatalf("GET Delivery Services missing: %v", dsXML) + t.Fatalf("GET Delivery Services missing: %s", *dsXML) } testCases := []struct { @@ -1375,13 +1428,13 @@ func UpdateValidateORGServerCacheGroup(t *testing.T) { t.Fatalf("Expected exactly one Delivery Service with the XMLID 'ds-top', found: %d", len(resp.Response)) } remoteDS := resp.Response[0] - if remoteDS.ID == nil || remoteDS.Topology == nil { - t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined ID and/or Topology") + if remoteDS.XMLID == nil || remoteDS.ID == nil || remoteDS.Topology == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service that had null or undefined XMLID and/or ID and/or Topology") } //Assign ORG server to DS assignServer := []string{"denver-mso-org-01"} - alerts, _, err := TOSession.AssignServersToDeliveryService(assignServer, remoteDS.XMLID, client.RequestOptions{}) + alerts, _, err := TOSession.AssignServersToDeliveryService(assignServer, *remoteDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("cannot assign server to Delivery Services: %v - alerts: %+v", err, alerts) } @@ -1497,21 +1550,25 @@ func DeleteTestDeliveryServices(t *testing.T) { t.Errorf("cannot get Delivery Services: %v - alerts: %+v", err, dses.Alerts) } for _, testDS := range testData.DeliveryServices { + if testDS.XMLID == nil { + t.Error("Found a Delivery Service in testing data with null or undefined XMLID") + continue + } var ds tc.DeliveryServiceV4 found := false for _, realDS := range dses.Response { - if realDS.ID == nil { - t.Errorf("Traffic Ops returned a representation for a Delivery Service with null or undefined ID") + if realDS.XMLID == nil || realDS.ID == nil { + t.Errorf("Traffic Ops returned a representation for a Delivery Service with null or undefined XMLID and/or ID") continue } - if realDS.XMLID == testDS.XMLID { + if *realDS.XMLID == *testDS.XMLID { ds = realDS found = true break } } if !found { - t.Errorf("DeliveryService not found in Traffic Ops: %v", testDS.XMLID) + t.Errorf("Delivery Service not found in Traffic Ops: %s", *testDS.XMLID) continue } @@ -1526,10 +1583,10 @@ func DeleteTestDeliveryServices(t *testing.T) { opts.QueryParameters.Set("id", strconv.Itoa(*ds.ID)) foundDS, _, err := TOSession.GetDeliveryServices(opts) if err != nil { - t.Errorf("Unexpected error deleting Delivery Service '%s': %v - alelts: %+v", ds.XMLID, err, foundDS.Alerts) + t.Errorf("Unexpected error deleting Delivery Service '%s': %v - alelts: %+v", *ds.XMLID, err, foundDS.Alerts) } if len(foundDS.Response) > 0 { - t.Errorf("expected Delivery Service: %s to be deleted, but %d exist with same ID (#%d)", ds.XMLID, len(foundDS.Response), *ds.ID) + t.Errorf("expected Delivery Service: %s to be deleted, but %d exist with same ID (#%d)", *ds.XMLID, len(foundDS.Response), *ds.ID) } } @@ -1553,8 +1610,11 @@ func DeliveryServiceMinorVersionsTest(t *testing.T) { t.Fatalf("Need at least 5 DSes to test minor versions; got: %d", len(testData.DeliveryServices)) } testDS := testData.DeliveryServices[4] - if testDS.XMLID != "ds-test-minor-versions" { - t.Errorf("expected XMLID: ds-test-minor-versions, actual: %s", testDS.XMLID) + if testDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } + if *testDS.XMLID != "ds-test-minor-versions" { + t.Errorf("expected XMLID: ds-test-minor-versions, actual: %s", *testDS.XMLID) } dses, _, err := TOSession.GetDeliveryServices(client.RequestOptions{}) @@ -1565,18 +1625,20 @@ func DeliveryServiceMinorVersionsTest(t *testing.T) { var ds tc.DeliveryServiceV4 found := false for _, d := range dses.Response { - if d.XMLID == testDS.XMLID { + if d.XMLID != nil && *d.XMLID == *testDS.XMLID { ds = d found = true break } } if !found { - t.Fatalf("Delivery Service '%s' not found in Traffic Ops", testDS.XMLID) + t.Fatalf("Delivery Service '%s' not found in Traffic Ops", *testDS.XMLID) } // GET latest, verify expected values for 1.3 and 1.4 fields - if ds.DeepCachingType != testDS.DeepCachingType { + if ds.DeepCachingType == nil { + t.Errorf("expected DeepCachingType: %s, actual: nil", testDS.DeepCachingType.String()) + } else if *ds.DeepCachingType != *testDS.DeepCachingType { t.Errorf("expected DeepCachingType: %s, actual: %s", testDS.DeepCachingType.String(), ds.DeepCachingType.String()) } if ds.FQPacingRate == nil { @@ -1636,11 +1698,11 @@ func DeliveryServiceTenancyTest(t *testing.T) { var tenant3DS tc.DeliveryServiceV4 foundTenant3DS := false for _, d := range dses.Response { - if d.ID == nil || d.Tenant == nil { - t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined ID and/or Tenant") + if d.XMLID == nil || d.ID == nil || d.Tenant == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID and/or ID and/or Tenant") continue } - if d.XMLID == "ds3" { + if *d.XMLID == "ds3" { tenant3DS = d foundTenant3DS = true } @@ -1662,24 +1724,28 @@ func DeliveryServiceTenancyTest(t *testing.T) { // assert that tenant4user cannot read deliveryservices outside of its tenant for _, ds := range dsesReadableByTenant4.Response { - if ds.XMLID == "ds3" { + if ds.XMLID == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID") + continue + } + if *ds.XMLID == "ds3" { t.Error("expected tenant4 to be unable to read delivery services from tenant 3") } } // assert that tenant4user cannot update tenant3user's deliveryservice if _, _, err = tenant4TOClient.UpdateDeliveryService(*tenant3DS.ID, tenant3DS, client.RequestOptions{}); err == nil { - t.Errorf("expected tenant4user to be unable to update tenant3's deliveryservice (%s)", tenant3DS.XMLID) + t.Errorf("expected tenant4user to be unable to update tenant3's deliveryservice (%s)", *tenant3DS.XMLID) } // assert that tenant4user cannot delete tenant3user's deliveryservice if _, _, err = tenant4TOClient.DeleteDeliveryService(*tenant3DS.ID, client.RequestOptions{}); err == nil { - t.Errorf("expected tenant4user to be unable to delete tenant3's deliveryservice (%s)", tenant3DS.XMLID) + t.Errorf("expected tenant4user to be unable to delete tenant3's deliveryservice (%s)", *tenant3DS.XMLID) } // assert that tenant4user cannot create a deliveryservice outside of its tenant - tenant3DS.XMLID = "deliveryservicetenancytest" - tenant3DS.DisplayName = "deliveryservicetenancytest" + tenant3DS.XMLID = util.StrPtr("deliveryservicetenancytest") + tenant3DS.DisplayName = util.StrPtr("deliveryservicetenancytest") if _, _, err = tenant4TOClient.CreateDeliveryService(tenant3DS, client.RequestOptions{}); err == nil { t.Error("expected tenant4user to be unable to create a deliveryservice outside of its tenant") } @@ -1762,24 +1828,27 @@ func GetDeliveryServiceByCdn(t *testing.T) { } opts := client.NewRequestOptions() - opts.QueryParameters.Set("name", *firstDS.CDNName) - cdns, _, err := TOSession.GetCDNs(opts) - if err != nil { - t.Errorf("Unexpected error getting CDN '%s' by name: %v - alerts: %+v", *firstDS.CDNName, err, cdns.Alerts) - } - if len(cdns.Response) != 1 { - t.Fatalf("Expected exactly one CDN named '%s' to exist, found: %d", *firstDS.CDNName, len(cdns.Response)) + if firstDS.CDNID == nil { + opts.QueryParameters.Set("name", *firstDS.CDNName) + cdns, _, err := TOSession.GetCDNs(opts) + if err != nil { + t.Errorf("Unexpected error getting CDN '%s' by name: %v - alerts: %+v", *firstDS.CDNName, err, cdns.Alerts) + } + if len(cdns.Response) != 1 { + t.Fatalf("Expected exactly one CDN named '%s' to exist, found: %d", *firstDS.CDNName, len(cdns.Response)) + } + firstDS.CDNID = new(int) + *firstDS.CDNID = cdns.Response[0].ID + opts.QueryParameters.Del("name") } - firstDS.CDNID = cdns.Response[0].ID - opts.QueryParameters.Del("name") - opts.QueryParameters.Set("cdn", strconv.Itoa(firstDS.CDNID)) + opts.QueryParameters.Set("cdn", strconv.Itoa(*firstDS.CDNID)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by CDN ID: %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Delivery Service to exist in CDN '%s' (#%d)", *firstDS.CDNName, firstDS.CDNID) + t.Fatalf("Expected at least one Delivery Service to exist in CDN '%s' (#%d)", *firstDS.CDNName, *firstDS.CDNID) } if resp.Response[0].CDNName == nil { t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined CDN Name") @@ -1866,8 +1935,11 @@ func GetTestDeliveryServicesURLSignatureKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } - _, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) + _, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("failed to get url sig keys: %v", err) } @@ -1879,11 +1951,15 @@ func CreateTestDeliveryServicesURLSignatureKeys(t *testing.T) { } firstDS := testData.DeliveryServices[0] - resp, _, err := TOSession.CreateDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } + + resp, _, err := TOSession.CreateDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error creaetting URL signing keys: %v - alerts: %+v", err, resp.Alerts) } - firstKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) + firstKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error getting URL signing keys: %v - alerts: %+v", err, firstKeys.Alerts) } @@ -1896,11 +1972,11 @@ func CreateTestDeliveryServicesURLSignatureKeys(t *testing.T) { } // Create new keys again and check that they are different - resp, _, err = TOSession.CreateDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) + resp, _, err = TOSession.CreateDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error creating URL signing keys: %v - alerts: %+v", err, resp.Alerts) } - secondKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) + secondKeys, _, err := TOSession.GetDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error getting URL signing keys: %v - alerts: %+v", err, secondKeys.Alerts) } @@ -1923,7 +1999,11 @@ func DeleteTestDeliveryServicesURLSignatureKeys(t *testing.T) { } firstDS := testData.DeliveryServices[0] - resp, _, err := TOSession.DeleteDeliveryServiceURLSignatureKeys(firstDS.XMLID, client.RequestOptions{}) + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } + + resp, _, err := TOSession.DeleteDeliveryServiceURLSignatureKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Errorf("Unexpected error deletining URL signing keys: %v - alerts: %+v", err, resp.Alerts) } @@ -1936,9 +2016,13 @@ func GetTestDeliveryServicesURISigningKeys(t *testing.T) { } firstDS := testData.DeliveryServices[0] - _, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } + + _, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", firstDS.XMLID, err) + t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", *firstDS.XMLID, err) } } @@ -1978,6 +2062,9 @@ func CreateTestDeliveryServicesURISigningKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } var keyset map[string]tc.URISignerKeyset @@ -1985,12 +2072,12 @@ func CreateTestDeliveryServicesURISigningKeys(t *testing.T) { t.Errorf("json.UnMarshal(): expected nil error, actual: %v", err) } - _, _, err := TOSession.CreateDeliveryServiceURISigningKeys(firstDS.XMLID, keyset, client.RequestOptions{}) + _, _, err := TOSession.CreateDeliveryServiceURISigningKeys(*firstDS.XMLID, keyset, client.RequestOptions{}) if err != nil { t.Error("failed to create uri sig keys: " + err.Error()) } - firstKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) + firstKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Error("failed to get uri sig keys: " + err.Error()) } @@ -2015,12 +2102,12 @@ func CreateTestDeliveryServicesURISigningKeys(t *testing.T) { t.Errorf("json.UnMarshal(): expected nil error, actual: %v", err) } - alerts, _, err := TOSession.CreateDeliveryServiceURISigningKeys(firstDS.XMLID, keyset2, client.RequestOptions{}) + alerts, _, err := TOSession.CreateDeliveryServiceURISigningKeys(*firstDS.XMLID, keyset2, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error creating URI Signature Keys for Delivery Service '%s': %v - alerts: %+v", firstDS.XMLID, err, alerts.Alerts) + t.Errorf("Unexpected error creating URI Signature Keys for Delivery Service '%s': %v - alerts: %+v", *firstDS.XMLID, err, alerts.Alerts) } - secondKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) + secondKeysBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { t.Error("failed to get uri sig keys: " + err.Error()) } @@ -2048,15 +2135,18 @@ func DeleteTestDeliveryServicesURISigningKeys(t *testing.T) { t.Fatal("couldn't get the xml ID of test DS") } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } - resp, _, err := TOSession.DeleteDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) + resp, _, err := TOSession.DeleteDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error deleting URI Signing keys for Delivery Service '%s': %v - alerts: %+v", firstDS.XMLID, err, resp.Alerts) + t.Errorf("Unexpected error deleting URI Signing keys for Delivery Service '%s': %v - alerts: %+v", *firstDS.XMLID, err, resp.Alerts) } - emptyBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(firstDS.XMLID, client.RequestOptions{}) + emptyBytes, _, err := TOSession.GetDeliveryServiceURISigningKeys(*firstDS.XMLID, client.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", firstDS.XMLID, err) + t.Errorf("Unexpected error getting URI signing keys for Delivery Service '%s': %v", *firstDS.XMLID, err) } emptyMap := make(map[string]interface{}) err = json.Unmarshal(emptyBytes, &emptyMap) @@ -2084,18 +2174,24 @@ func GetDeliveryServiceByLogsEnabled(t *testing.T) { t.Fatal("Need at least one Delivery Service to test getting Delivery Services filtered by their Logs Enabled property") } firstDS := testData.DeliveryServices[0] + if firstDS.LogsEnabled == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined LogsEnabled") + } opts := client.NewRequestOptions() - opts.QueryParameters.Set("logsEnabled", strconv.FormatBool(firstDS.LogsEnabled)) + opts.QueryParameters.Set("logsEnabled", strconv.FormatBool(*firstDS.LogsEnabled)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by 'logsEnabled': %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Delivery Service to exist with Logs Enabled set to %t", firstDS.LogsEnabled) + t.Fatalf("Expected at least one Delivery Service to exist with Logs Enabled set to %t", *firstDS.LogsEnabled) + } + if resp.Response[0].LogsEnabled == nil { + t.Fatal("Traffic Ops returned a representation for a Delivery Service with null or undefined Logs Enabled property") } - if resp.Response[0].LogsEnabled != firstDS.LogsEnabled { - t.Errorf("Logs enabled status expected: %t, actual: %t", firstDS.LogsEnabled, resp.Response[0].LogsEnabled) + if *resp.Response[0].LogsEnabled != *firstDS.LogsEnabled { + t.Errorf("Logs enabled status expected: %t, actual: %t", *firstDS.LogsEnabled, *resp.Response[0].LogsEnabled) } } @@ -2151,18 +2247,21 @@ func GetDeliveryServiceByValidTenant(t *testing.T) { } opts := client.NewRequestOptions() - opts.QueryParameters.Set("name", *firstDS.Tenant) - tenants, _, err := TOSession.GetTenants(opts) - if err != nil { - t.Errorf("Unexpected error getting Tenants filtered by name: %v - alerts: %+v", err, tenants.Alerts) - } - if len(tenants.Response) != 1 { - t.Fatalf("Expected exactly one Tenant to exist with name '%s', found %d:", *firstDS.Tenant, len(tenants.Response)) + if firstDS.TenantID == nil { + opts.QueryParameters.Set("name", *firstDS.Tenant) + tenants, _, err := TOSession.GetTenants(opts) + if err != nil { + t.Errorf("Unexpected error getting Tenants filtered by name: %v - alerts: %+v", err, tenants.Alerts) + } + if len(tenants.Response) != 1 { + t.Fatalf("Expected exactly one Tenant to exist with name '%s', found %d:", *firstDS.Tenant, len(tenants.Response)) + } + firstDS.TenantID = new(int) + *firstDS.TenantID = tenants.Response[0].ID + opts.QueryParameters.Del("name") } - firstDS.TenantID = tenants.Response[0].ID - opts.QueryParameters.Del("name") - opts.QueryParameters.Set("tenant", strconv.Itoa(firstDS.TenantID)) + opts.QueryParameters.Set("tenant", strconv.Itoa(*firstDS.TenantID)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by Tenant ID: %v - alerts: %+v", err, resp.Alerts) @@ -2188,24 +2287,27 @@ func GetDeliveryServiceByValidType(t *testing.T) { } opts := client.NewRequestOptions() - opts.QueryParameters.Set("name", firstDS.Type.String()) - types, _, err := TOSession.GetTypes(opts) - if err != nil { - t.Errorf("Unexpected error getting Types filtered by name: %v - alerts: %+v", err, types.Alerts) - } - if len(types.Response) != 1 { - t.Fatalf("Expected exactly one Type to exist with name '%s', found %d:", *firstDS.Type, len(types.Response)) + if firstDS.TypeID == nil { + opts.QueryParameters.Set("name", firstDS.Type.String()) + types, _, err := TOSession.GetTypes(opts) + if err != nil { + t.Errorf("Unexpected error getting Types filtered by name: %v - alerts: %+v", err, types.Alerts) + } + if len(types.Response) != 1 { + t.Fatalf("Expected exactly one Type to exist with name '%s', found %d:", *firstDS.Type, len(types.Response)) + } + firstDS.TypeID = new(int) + *firstDS.TypeID = types.Response[0].ID + opts.QueryParameters.Del("name") } - firstDS.TypeID = types.Response[0].ID - opts.QueryParameters.Del("name") - opts.QueryParameters.Set("type", strconv.Itoa(firstDS.TypeID)) + opts.QueryParameters.Set("type", strconv.Itoa(*firstDS.TypeID)) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by Type ID: %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) == 0 { - t.Fatalf("Expected at least one Delivery Service to exist with Type '%s' (#%d)", *firstDS.Type, firstDS.TypeID) + t.Fatalf("Expected at least one Delivery Service to exist with Type '%s' (#%d)", *firstDS.Type, *firstDS.TypeID) } if resp.Response[0].Type == nil { t.Fatal("Traffic Ops returned a representation of a Delivery Service with null or undefined Type Name") @@ -2221,17 +2323,24 @@ func GetDeliveryServiceByValidXmlId(t *testing.T) { } firstDS := testData.DeliveryServices[0] + if firstDS.XMLID == nil { + t.Fatal("Found a Delivery Service in testing data with a null or undefined XMLID") + } + opts := client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", firstDS.XMLID) + opts.QueryParameters.Set("xmlId", *firstDS.XMLID) resp, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Errorf("Unexpected error getting Delivery Services filtered by XMLID: %v - alerts: %+v", err, resp.Alerts) } if len(resp.Response) != 1 { - t.Fatalf("Expected exactly one Delivery Service to exist with XMLID '%s', found: %d", firstDS.XMLID, len(resp.Response)) + t.Fatalf("Expected exactly one Delivery Service to exist with XMLID '%s', found: %d", *firstDS.XMLID, len(resp.Response)) + } + if resp.Response[0].XMLID == nil { + t.Fatal("Traffic Ops returned a representation of a Delivery Service with null or undefined XMLID") } - if resp.Response[0].XMLID != firstDS.XMLID { - t.Errorf("Delivery Service XMLID expected: %s, actual: %s", firstDS.XMLID, resp.Response[0].XMLID) + if *resp.Response[0].XMLID != *firstDS.XMLID { + t.Errorf("Delivery Service XMLID expected: %s, actual: %s", *firstDS.XMLID, *resp.Response[0].XMLID) } } @@ -2263,8 +2372,10 @@ func SortTestDeliveryServicesDesc(t *testing.T) { for start, end := 0, len(respDesc)-1; start < end; start, end = start+1, end-1 { respDesc[start], respDesc[end] = respDesc[end], respDesc[start] } - if !reflect.DeepEqual(respDesc[0].XMLID, respAsc[0].XMLID) { - t.Errorf("Delivery Service responses are not equal after reversal: %v - %v", respDesc[0].XMLID, respAsc[0].XMLID) + if respDesc[0].XMLID != nil && respAsc[0].XMLID != nil { + if !reflect.DeepEqual(respDesc[0].XMLID, respAsc[0].XMLID) { + t.Errorf("Delivery Service responses are not equal after reversal: %v - %v", *respDesc[0].XMLID, *respAsc[0].XMLID) + } } } @@ -2279,7 +2390,7 @@ func addTLSVersionsToDeliveryService(t *testing.T) { ds := tc.DeliveryServiceV4{ CDNName: new(string), - DisplayName: "ds-test-tls-versions", + DisplayName: new(string), InitialDispersion: new(int), MissLat: new(float64), MissLong: new(float64), @@ -2289,15 +2400,17 @@ func addTLSVersionsToDeliveryService(t *testing.T) { QStringIgnore: new(int), RangeRequestHandling: new(int), Tenant: new(string), - TenantID: *me.Response.TenantID, + TenantID: me.Response.TenantID, TLSVersions: []string{ "1.1", }, Type: new(tc.DSType), - XMLID: "ds-test-tls-versions", + XMLID: new(string), } *ds.InitialDispersion = 1 *ds.Tenant = *me.Response.Tenant + *ds.DisplayName = "ds-test-tls-versions" + *ds.XMLID = "ds-test-tls-versions" cdns, _, err := TOSession.GetCDNs(client.RequestOptions{}) if err != nil { @@ -2306,7 +2419,7 @@ func addTLSVersionsToDeliveryService(t *testing.T) { if len(cdns.Response) < 1 { t.Fatalf("Need at least one CDN to exist in order to test Delivery Service TLS Versions") } - ds.CDNID = cdns.Response[0].ID + ds.CDNID = &cdns.Response[0].ID *ds.CDNName = cdns.Response[0].Name *ds.Type = "STEERING" @@ -2319,7 +2432,7 @@ func addTLSVersionsToDeliveryService(t *testing.T) { if len(types.Response) != 1 { t.Fatalf("Expected exactly one Type to exist named 'STEERING', found: %d", len(types.Response)) } - ds.TypeID = types.Response[0].ID + ds.TypeID = &types.Response[0].ID _, _, err = TOSession.CreateDeliveryService(ds, client.RequestOptions{}) if err == nil { @@ -2337,7 +2450,7 @@ func addTLSVersionsToDeliveryService(t *testing.T) { if len(types.Response) != 1 { t.Fatalf("Expected exactly one Type to exist named 'HTTP', found: %d", len(types.Response)) } - ds.TypeID = types.Response[0].ID + ds.TypeID = &types.Response[0].ID *ds.OrgServerFQDN = "https://origin.test" resp, _, err := TOSession.CreateDeliveryService(ds, client.RequestOptions{}) diff --git a/traffic_ops/testing/api/v4/deliveryserviceservers_test.go b/traffic_ops/testing/api/v4/deliveryserviceservers_test.go index e074959545..72f0dc6082 100644 --- a/traffic_ops/testing/api/v4/deliveryserviceservers_test.go +++ b/traffic_ops/testing/api/v4/deliveryserviceservers_test.go @@ -229,13 +229,13 @@ func AssignServersToTopologyBasedDeliveryService(t *testing.T) { t.Fatalf("expected one delivery service: 'ds-top', actual: %v", len(ds.Response)) } d := ds.Response[0] - if d.Topology == nil || d.ID == nil || d.CDNName == nil { - t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or CDN Name and/or ID") + if d.Topology == nil || d.ID == nil || d.CDNID == nil || d.CDNName == nil { + t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or CDN ID and/or CDN Name and/or ID") } serversResp, _, err := TOSession.GetServers(client.RequestOptions{}) servers := []tc.ServerV4{} for _, s := range serversResp.Response { - if s.CDNID != nil && *s.CDNID == d.CDNID && s.Type == tc.CacheTypeEdge.String() { + if s.CDNID != nil && *s.CDNID == *d.CDNID && s.Type == tc.CacheTypeEdge.String() { servers = append(servers, s) } } @@ -247,7 +247,7 @@ func AssignServersToTopologyBasedDeliveryService(t *testing.T) { } serverNames := []string{} for _, s := range servers { - if s.CDNID != nil && s.HostName != nil && *s.CDNID == d.CDNID && s.Type == tc.CacheTypeEdge.String() { + if s.CDNID != nil && s.HostName != nil && *s.CDNID == *d.CDNID && s.Type == tc.CacheTypeEdge.String() { serverNames = append(serverNames, *s.HostName) } else { t.Fatalf("expected only EDGE servers in cdn '%s', actual: %v", *d.CDNName, servers) @@ -353,8 +353,8 @@ func AssignServersToNonTopologyBasedDeliveryServiceThatUsesMidTier(t *testing.T) if dsWithMid.Topology != nil { t.Fatal("expected delivery service: 'ds1' to have a nil Topology, actual: non-nil") } - if dsWithMid.CDNName == nil || dsWithMid.ID == nil { - t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined CDN Name and/or ID") + if dsWithMid.CDNID == nil || dsWithMid.CDNName == nil || dsWithMid.ID == nil { + t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined CDN ID and/or CDN Name and/or ID") } serversResp, _, err := TOSession.GetServers(client.RequestOptions{}) if err != nil { @@ -362,7 +362,7 @@ func AssignServersToNonTopologyBasedDeliveryServiceThatUsesMidTier(t *testing.T) } serversIds := []int{} for _, s := range serversResp.Response { - if s.CDNID != nil && *s.CDNID == dsWithMid.CDNID && s.Type == tc.CacheTypeEdge.String() { + if s.CDNID != nil && *s.CDNID == *dsWithMid.CDNID && s.Type == tc.CacheTypeEdge.String() { serversIds = append(serversIds, *s.ID) } } @@ -389,7 +389,7 @@ func AssignServersToNonTopologyBasedDeliveryServiceThatUsesMidTier(t *testing.T) } for _, dss := range dsServersResp.Response { - if dss.CDNID != nil && *dss.CDNID != dsWithMid.CDNID { + if dss.CDNID != nil && *dss.CDNID != *dsWithMid.CDNID { t.Fatalf("a server for another cdn was returned for this delivery service") } } @@ -580,6 +580,9 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { if ds.ID == nil { t.Fatalf("Got a delivery service with a nil ID %+v", ds) } + if ds.Active == nil { + t.Fatalf("Got a Delivery Service with nil 'Active': %+v", ds) + } resp, _, err := TOSession.CreateDeliveryServiceServers(*ds.ID, []int{*server.ID}, true, client.RequestOptions{}) if err != nil { @@ -602,8 +605,8 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { t.Error("POST delivery service servers returned success, but ds-server not in GET") } - if ds.Active { - ds.Active = false + if *ds.Active { + *ds.Active = false _, _, err = TOSession.UpdateDeliveryService(*ds.ID, ds, client.RequestOptions{}) if err != nil { t.Errorf("Setting Delivery Service #%d to inactive", *ds.ID) diff --git a/traffic_ops/testing/api/v4/federations_test.go b/traffic_ops/testing/api/v4/federations_test.go index 60f8d6e1ce..071bb3dc74 100644 --- a/traffic_ops/testing/api/v4/federations_test.go +++ b/traffic_ops/testing/api/v4/federations_test.go @@ -223,14 +223,14 @@ func AddFederationResolversForCurrentUserTest(t *testing.T) { mappings := tc.DeliveryServiceFederationResolverMappingRequest{ tc.DeliveryServiceFederationResolverMapping{ - DeliveryService: ds.XMLID, + DeliveryService: *ds.XMLID, Mappings: tc.ResolverMapping{ Resolve4: []string{"0.0.0.0"}, Resolve6: []string{"::1"}, }, }, tc.DeliveryServiceFederationResolverMapping{ - DeliveryService: ds1.XMLID, + DeliveryService: *ds1.XMLID, Mappings: tc.ResolverMapping{ Resolve4: []string{"1.2.3.4/28"}, Resolve6: []string{"1234::/110"}, diff --git a/traffic_ops/testing/api/v4/jobs_test.go b/traffic_ops/testing/api/v4/jobs_test.go index c560c1e6cf..9c41b6b25b 100644 --- a/traffic_ops/testing/api/v4/jobs_test.go +++ b/traffic_ops/testing/api/v4/jobs_test.go @@ -71,7 +71,10 @@ func JobCollisionWarningTest(t *testing.T) { if len(testData.DeliveryServices) < 1 { t.Fatal("Need at least one Delivery Service to test Invalidation Job collisions") } - xmlID := testData.DeliveryServices[0].XMLID + if testData.DeliveryServices[0].XMLID == nil { + t.Fatal("Found a Delivery Service in the testing data with null or undefined XMLID") + } + xmlID := *testData.DeliveryServices[0].XMLID startTime := tc.Time{ Time: time.Now().Add(time.Hour), @@ -172,11 +175,11 @@ func CreateTestInvalidationJobs(t *testing.T) { } dsNameIDs := make(map[string]int64, len(toDSes.Response)) for _, ds := range toDSes.Response { - if ds.ID == nil { - t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined ID") + if ds.XMLID == nil || ds.ID == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID and/or ID") continue } - dsNameIDs[ds.XMLID] = int64(*ds.ID) + dsNameIDs[*ds.XMLID] = int64(*ds.ID) } for _, job := range testData.InvalidationJobs { @@ -200,11 +203,11 @@ func CreateTestInvalidJob(t *testing.T) { } dsNameIDs := make(map[string]int64, len(toDSes.Response)) for _, ds := range toDSes.Response { - if ds.ID == nil { + if ds.XMLID == nil || ds.ID == nil { t.Error("Traffic Ops returned a representation of a Delivery Service that had null or undefined XMLID and/or ID") continue } - dsNameIDs[ds.XMLID] = int64(*ds.ID) + dsNameIDs[*ds.XMLID] = int64(*ds.ID) } if len(testData.InvalidationJobs) < 1 { diff --git a/traffic_ops/testing/api/v4/servers_test.go b/traffic_ops/testing/api/v4/servers_test.go index a3f7ba6298..ddc1c126b6 100644 --- a/traffic_ops/testing/api/v4/servers_test.go +++ b/traffic_ops/testing/api/v4/servers_test.go @@ -593,11 +593,11 @@ func GetTestServersQueryParameters(t *testing.T) { topology = "mso-topology" ) for _, ds = range dses.Response { - if ds.ID == nil { - t.Error("Traffic Ops returned a representation of a Delivery Service that had a null or undefined ID") + if ds.XMLID == nil || ds.ID == nil { + t.Error("Traffic Ops returned a representation of a Delivery Service that had a null or undefined XMLID and/or ID") continue } - if ds.XMLID != topDSXmlID { + if *ds.XMLID != topDSXmlID { continue } if ds.Topology == nil || ds.FirstHeaderRewrite == nil || ds.InnerHeaderRewrite == nil || ds.LastHeaderRewrite == nil { diff --git a/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go b/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go index 4c6490890e..66676db948 100644 --- a/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go +++ b/traffic_ops/testing/api/v4/servers_to_deliveryservice_assignment_test.go @@ -56,8 +56,12 @@ func AssignTestDeliveryService(t *testing.T) { t.Fatalf("Server '%s' had nil ID", *server.HostName) } + if testData.DeliveryServices[0].XMLID == nil { + t.Fatal("Found Delivery Service in testing data with null or undefined XMLID") + } + opts.QueryParameters.Del("hostName") - opts.QueryParameters.Set("xmlId", testData.DeliveryServices[0].XMLID) + opts.QueryParameters.Set("xmlId", *testData.DeliveryServices[0].XMLID) rd, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Fatalf("Failed to fetch DS information: %v - alerts: %+v", err, rd.Alerts) @@ -134,9 +138,12 @@ func AssignIncorrectTestDeliveryService(t *testing.T) { if len(testData.DeliveryServices) < 1 { t.Fatal("Need at least one Delivery Service to test assignment of servers to Delivery Services") } + if testData.DeliveryServices[0].XMLID == nil { + t.Fatal("Delivery Service selected for testing had null or undefined XMLID") + } opts = client.NewRequestOptions() - opts.QueryParameters.Set("xmlId", testData.DeliveryServices[0].XMLID) + opts.QueryParameters.Set("xmlId", *testData.DeliveryServices[0].XMLID) rd, _, err := TOSession.GetDeliveryServices(opts) if err != nil { t.Fatalf("Failed to fetch DS information: %v - alerts: %+v", err, rd.Alerts) diff --git a/traffic_ops/testing/api/v4/tenants_test.go b/traffic_ops/testing/api/v4/tenants_test.go index 81be79af2f..3c649ffa2c 100644 --- a/traffic_ops/testing/api/v4/tenants_test.go +++ b/traffic_ops/testing/api/v4/tenants_test.go @@ -286,6 +286,13 @@ func DeleteTestTenants(t *testing.T) { } } +func ExtractXMLID(ds *tc.DeliveryServiceV4) string { + if ds.XMLID != nil { + return *ds.XMLID + } + return "nil" +} + func UpdateTestTenantsActive(t *testing.T) { originalTenants, _, err := TOSession.GetTenants(client.RequestOptions{}) if err != nil { @@ -333,7 +340,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds3': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 parent tenant2 is inactive, expected: no ds", ds.XMLID) + t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 parent tenant2 is inactive, expected: no ds", ExtractXMLID(&ds)) } setTenantActive(t, "tenant1", true) @@ -346,7 +353,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds3': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 is inactive, expected: no ds", ds.XMLID) + t.Errorf("tenant3user got delivery service %s with tenant3 but tenant3 is inactive, expected: no ds", ExtractXMLID(&ds)) } setTenantActive(t, "tenant1", true) @@ -371,7 +378,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds2': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user got delivery service %s with tenant2, expected: no ds", ds.XMLID) + t.Errorf("tenant3user got delivery service %s with tenant2, expected: no ds", ExtractXMLID(&ds)) } // 1. ds1 has tenant1. @@ -384,7 +391,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds1': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant4user got delivery service %s with tenant1, expected: no ds", ds.XMLID) + t.Errorf("tenant4user got delivery service %s with tenant1, expected: no ds", ExtractXMLID(&ds)) } setTenantActive(t, "tenant3", false) @@ -394,7 +401,7 @@ func UpdateTestTenantsActive(t *testing.T) { t.Errorf("Unexpected error fetching Delivery Services filtered by XMLID 'ds3': %v - alerts: %+v", err, resp.Alerts) } for _, ds := range resp.Response { - t.Errorf("tenant3user was inactive, but got delivery service %s with tenant3, expected: no ds", ds.XMLID) + t.Errorf("tenant3user was inactive, but got delivery service %s with tenant3, expected: no ds", ExtractXMLID(&ds)) } for _, tn := range originalTenants.Response { diff --git a/traffic_ops/testing/api/v4/topologies_queue_update_test.go b/traffic_ops/testing/api/v4/topologies_queue_update_test.go index 0c1db6b42e..577bb045d0 100644 --- a/traffic_ops/testing/api/v4/topologies_queue_update_test.go +++ b/traffic_ops/testing/api/v4/topologies_queue_update_test.go @@ -56,10 +56,10 @@ func getCDNIDAndDSID(t *testing.T) (int64, int) { t.Fatalf("deliveryservice with xmlId '%s' not found!", xmlID) } ds := dses.Response[0] - if ds.ID == nil { - t.Fatalf("Traffic Ops returned a representation of a Delivery Service that had null or undefined ID") + if ds.CDNID == nil || ds.ID == nil { + t.Fatalf("Traffic Ops returned a representation of a Delivery Service that had null or undefined CDN ID and/or ID") } - return int64(ds.CDNID), *ds.ID + return int64(*ds.CDNID), *ds.ID } func InvalidCDNIDIsRejected(t *testing.T, topologyName string) { diff --git a/traffic_ops/testing/api/v4/topologies_test.go b/traffic_ops/testing/api/v4/topologies_test.go index 470d57a61a..a280ecf2fa 100644 --- a/traffic_ops/testing/api/v4/topologies_test.go +++ b/traffic_ops/testing/api/v4/topologies_test.go @@ -353,15 +353,15 @@ func UpdateValidateTopologyORGServerCacheGroup(t *testing.T) { t.Fatalf("Expected exactly one Delivery Service to exist with XMLID 'ds-top', found: %d", len(resp.Response)) } remoteDS := resp.Response[0] - if remoteDS.Topology == nil || remoteDS.ID == nil { - t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or ID") + if remoteDS.XMLID == nil || remoteDS.Topology == nil || remoteDS.ID == nil { + t.Fatal("Traffic Ops returned a representation of a Delivery Service that had null or undefined Topology and/or XMLID and/or ID") } //Assign ORG server to DS assignServer := []string{"denver-mso-org-01"} - assignResponse, _, err := TOSession.AssignServersToDeliveryService(assignServer, remoteDS.XMLID, toclient.RequestOptions{}) + assignResponse, _, err := TOSession.AssignServersToDeliveryService(assignServer, *remoteDS.XMLID, toclient.RequestOptions{}) if err != nil { - t.Errorf("Unexpected error assigning server 'denver-mso-org-01' to Delivery Service '%s': %v - alerts: %+v", remoteDS.XMLID, err, assignResponse.Alerts) + t.Errorf("Unexpected error assigning server 'denver-mso-org-01' to Delivery Service '%s': %v - alerts: %+v", *remoteDS.XMLID, err, assignResponse.Alerts) } //Get Topology node to update and remove ORG server nodes diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go index 0f50f9ac89..ac42b121ec 100644 --- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go +++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go @@ -925,8 +925,9 @@ func CheckTopology(tx *sqlx.Tx, ds tc.DeliveryServiceV4) (int, error, error) { return http.StatusBadRequest, fmt.Errorf("no such Topology '%s'", *ds.Topology), nil } - if err = topology_validation.CheckForEmptyCacheGroups(tx, cacheGroupIDs, []int{ds.CDNID}, true, []int{}); err != nil { - return http.StatusBadRequest, fmt.Errorf("empty cachegroups in Topology %s found for CDN %d: %w", *ds.Topology, ds.CDNID, err), nil + // note that this segfaults if the ds doesn't have a properly set CDNID + if err = topology_validation.CheckForEmptyCacheGroups(tx, cacheGroupIDs, []int{*ds.CDNID}, true, []int{}); err != nil { + return http.StatusBadRequest, fmt.Errorf("empty cachegroups in Topology %s found for CDN %d: %w", *ds.Topology, *ds.CDNID, err), nil } return statusCode, userErr, sysErr diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index f219629c94..44414ace26 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -95,7 +95,10 @@ func (ds TODeliveryService) GetKeyFieldsInfo() []api.KeyFieldInfo { } func (ds *TODeliveryService) GetAuditName() string { - return ds.XMLID + if ds.XMLID != nil { + return *ds.XMLID + } + return "" } func (ds *TODeliveryService) GetType() string { @@ -126,10 +129,6 @@ func CreateV12(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV12{*res}) } @@ -152,10 +151,6 @@ func CreateV13(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV13{*res}) } @@ -178,10 +173,6 @@ func CreateV14(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV14{*res}) } @@ -206,10 +197,6 @@ func CreateV15(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV15{*res}) } @@ -232,10 +219,6 @@ func CreateV30(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV30{*res}) } @@ -258,10 +241,6 @@ func CreateV31(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV31{*res}) } @@ -284,10 +263,6 @@ func CreateV40(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil || res.ID == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("creation response Delivery Service was nil or had nil ID")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") w.Header().Set("Location", fmt.Sprintf("/api/4.0/deliveryservices?id=%d", *res.ID)) api.WriteAlertsObj(w, r, http.StatusCreated, alerts, []tc.DeliveryServiceV40{*res}) @@ -353,7 +328,7 @@ func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 t } } - if err := EnsureCacheURLParams(tx, *ds.ID, ds.XMLID, dsV31.CacheURL); err != nil { + if err := EnsureCacheURLParams(tx, *ds.ID, *ds.XMLID, dsV31.CacheURL); err != nil { return nil, alerts, http.StatusInternalServerError, nil, err } @@ -399,14 +374,15 @@ func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { } // generates warning-level alerts (if any are necessary) for a Delivery Service -// based on its TLS Versions. This will panic if handed a nil transaction. +// based on its TLS Versions. This will panic if handed a nil transaction, or +// if the given Delivery Service has a nil TypeID. func generateTLSVersionWarnings(ds tc.DeliveryServiceV4, tx *sql.Tx) tc.Alerts { alerts := tc.TLSVersionsAlerts(ds.TLSVersions) var httpType int if err := tx.QueryRow(`SELECT id FROM public.type WHERE name = 'HTTP'`).Scan(&httpType); err != nil { log.Errorln("Failed to get 'HTTP' type: ", err.Error()) - } else if httpType == ds.TypeID { + } else if httpType == *ds.TypeID { if len(ds.TLSVersions) >= 1 { alerts.AddNewAlert(tc.WarnLevel, "tlsVersions has no effect on 'HTTP' Delivery Services") } @@ -435,7 +411,10 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t } // TODO change DeepCachingType to implement sql.Valuer and sql.Scanner, so sqlx struct scan can be used. - deepCachingType := ds.DeepCachingType.String() // necessary, because DeepCachingType's default needs to insert the string, not "", and Query doesn't call .String(). + deepCachingType := tc.DeepCachingType("").String() + if ds.DeepCachingType != nil { + 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, alerts, errCode, userErr, sysErr @@ -590,7 +569,17 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t if ds.ID == nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing id after insert") } - dsType, err := getTypeFromID(ds.TypeID, tx) + if ds.XMLID == nil { + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing xml_id after insert") + } + if ds.TypeID == nil { + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing type id after insert") + } + if ds.RoutingName == nil { + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing routing name after insert") + } + + dsType, err := getTypeFromID(*ds.TypeID, tx) if err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type: " + err.Error()) } @@ -605,7 +594,7 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t } } - if err := createDefaultRegex(tx, *ds.ID, ds.XMLID); err != nil { + if err := createDefaultRegex(tx, *ds.ID, *ds.XMLID); err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating default regex: " + err.Error()) } @@ -614,11 +603,11 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t return nil, alerts, code, usrErr, sysErr } - matchlists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx) + matchlists, err := GetDeliveryServicesMatchLists([]string{*ds.XMLID}, tx) if err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: " + err.Error()) } - if matchlist, ok := matchlists[ds.XMLID]; !ok { + if matchlist, ok := matchlists[*ds.XMLID]; !ok { return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: not found") } else { ds.MatchList = matchlist @@ -629,9 +618,9 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: getting CDN info: " + err.Error()) } - ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *ds.Type, ds.RoutingName, ds.MatchList, cdnDomain) + ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *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 { + if err := EnsureParams(tx, *ds.ID, *ds.XMLID, ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.SigningAlgorithm, dsType, ds.MaxOriginConnections); err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) } @@ -639,7 +628,7 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t if !inf.Config.TrafficVaultEnabled { return nil, alerts, 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 { + if userErr, sysErr, statusCode := PutDNSSecKeys(tx, *ds.XMLID, cdnName, ds.ExampleURLs, inf.Vault, r.Context()); userErr != nil || sysErr != nil { return nil, alerts, statusCode, userErr, sysErr } } @@ -649,7 +638,7 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t } 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 { + if err := api.CreateChangeLogRawErr(api.ApiChange, "DS: "+*ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Created delivery service", user, tx); err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("error writing to audit log: " + err.Error()) } @@ -751,10 +740,6 @@ func UpdateV12(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV12{*res}) } @@ -780,10 +765,6 @@ func UpdateV13(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV13{*res}) } @@ -809,10 +790,6 @@ func UpdateV14(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV14{*res}) } @@ -838,10 +815,6 @@ func UpdateV15(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV15{*res}) } @@ -867,10 +840,6 @@ func UpdateV30(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV30{*res}) } @@ -895,10 +864,6 @@ func UpdateV31(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV31{*res}) } @@ -923,10 +888,6 @@ func UpdateV40(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - if res == nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("update response Delivery Service was nil")) - return - } alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV40{*res}) } @@ -1099,7 +1060,7 @@ func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 * } } - if err := EnsureCacheURLParams(tx, *ds.ID, ds.XMLID, dsV31.CacheURL); err != nil { + if err := EnsureCacheURLParams(tx, *ds.ID, *ds.XMLID, dsV31.CacheURL); err != nil { return nil, alerts, http.StatusInternalServerError, nil, err } @@ -1121,13 +1082,16 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * return nil, alerts, http.StatusForbidden, errors.New("not authorized on this tenant"), nil } + if ds.XMLID == nil { + return nil, alerts, http.StatusBadRequest, errors.New("missing xml_id"), nil + } if ds.ID == nil { return nil, alerts, http.StatusBadRequest, errors.New("missing id"), nil } - dsType, ok, err := getDSType(tx, ds.XMLID) + dsType, ok, err := getDSType(tx, *ds.XMLID) if !ok { - return nil, alerts, http.StatusNotFound, errors.New("delivery service '" + ds.XMLID + "' not found"), nil + return nil, alerts, http.StatusNotFound, errors.New("delivery service '" + *ds.XMLID + "' not found"), nil } if err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type during update: " + err.Error()) @@ -1143,17 +1107,20 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if userErr != nil || sysErr != nil { return nil, alerts, errCode, userErr, sysErr } - if sslKeysExist, err = getSSLVersion(ds.XMLID, tx); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %s", err) + if sslKeysExist, err = getSSLVersion(*ds.XMLID, tx); err != nil { + return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %w", err) + } + if ds.CDNID == nil { + return nil, alerts, http.StatusBadRequest, errors.New("invalid request: 'cdnId' cannot be blank"), nil } if sslKeysExist { - if oldDetails.OldCdnId != ds.CDNID { + if oldDetails.OldCdnId != *ds.CDNID { cdnRoutingDetailDiff = true } if ds.CDNName != nil && oldDetails.OldCdnName != *ds.CDNName { cdnRoutingDetailDiff = true } - if oldDetails.OldRoutingName != ds.RoutingName { + if ds.RoutingName != nil && oldDetails.OldRoutingName != *ds.RoutingName { cdnRoutingDetailDiff = true } if cdnRoutingDetailDiff { @@ -1164,7 +1131,10 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * } // TODO change DeepCachingType to implement sql.Valuer and sql.Scanner, so sqlx struct scan can be used. - deepCachingType := ds.DeepCachingType.String() // necessary, because DeepCachingType's default needs to insert the string, not "", and Query doesn't call .String(). + deepCachingType := tc.DeepCachingType("").String() + if ds.DeepCachingType != nil { + 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 { @@ -1333,24 +1303,35 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * return nil, alerts, http.StatusInternalServerError, nil, errors.New("scan updating delivery service: " + err.Error()) } if resultRows.Next() { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("updating delivery service " + ds.XMLID + ": " + "this update affected too many rows: > 1") - } + xmlID := "" + if ds.XMLID != nil { + xmlID = *ds.XMLID + } + return nil, alerts, http.StatusInternalServerError, nil, errors.New("updating delivery service " + xmlID + ": " + "this update affected too many rows: > 1") + } if ds.ID == nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing id after update") } + if ds.XMLID == nil { + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing XMLID after update") + } + if ds.TypeID == nil { + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing type id after update") + } + if ds.RoutingName == nil { + return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing routing name after update") + } - if inf.Version != nil && inf.Version.Major >= 4 { - if len(ds.TLSVersions) < 1 { - ds.TLSVersions = nil - } - err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx) - if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("updating TLS versions for DS #%d: %w", *ds.ID, err) - } + if len(ds.TLSVersions) < 1 { + ds.TLSVersions = nil + } + err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx) + if err != nil { + return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("updating TLS versions for DS #%d: %w", *ds.ID, err) } - newDSType, err := getTypeFromID(ds.TypeID, tx) + newDSType, err := getTypeFromID(*ds.TypeID, tx) if err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type after update: " + err.Error()) } @@ -1361,17 +1342,17 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting CDN domain: (" + cdnDomain + ") after update: " + err.Error()) } - matchLists, err := GetDeliveryServicesMatchLists([]string{ds.XMLID}, tx) + matchLists, err := GetDeliveryServicesMatchLists([]string{*ds.XMLID}, tx) if err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting matchlists after update: " + err.Error()) } - if ml, ok := matchLists[ds.XMLID]; !ok { + if ml, ok := matchLists[*ds.XMLID]; !ok { return nil, alerts, http.StatusInternalServerError, nil, errors.New("no matchlists after update") } else { ds.MatchList = ml } - if err := EnsureParams(tx, *ds.ID, ds.XMLID, ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.SigningAlgorithm, newDSType, ds.MaxOriginConnections); err != nil { + if err := EnsureParams(tx, *ds.ID, *ds.XMLID, ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.SigningAlgorithm, newDSType, ds.MaxOriginConnections); err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) } @@ -1386,9 +1367,9 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * // 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, alerts, http.StatusInternalServerError, nil, fmt.Errorf("deleting consistent hash query params for ds %s: %w", ds.XMLID, err) + return nil, alerts, 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) + 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 { @@ -1396,7 +1377,7 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * return nil, alerts, code, usrErr, sysErr } - if err := api.CreateChangeLogRawErr(api.ApiChange, "Updated ds: "+ds.XMLID+" id: "+strconv.Itoa(*ds.ID), user, tx); err != nil { + if err := api.CreateChangeLogRawErr(api.ApiChange, "Updated ds: "+*ds.XMLID+" id: "+strconv.Itoa(*ds.ID), user, tx); err != nil { return nil, alerts, http.StatusInternalServerError, nil, errors.New("writing change log entry: " + err.Error()) } @@ -1418,7 +1399,7 @@ func (ds *TODeliveryService) Delete() (error, error, int) { } else if !ok { return errors.New("delivery service not found"), nil, http.StatusNotFound } - ds.XMLID = xmlID + ds.XMLID = &xmlID // Note ds regexes MUST be deleted before the ds, because there's a ON DELETE CASCADE on deliveryservice_regex (but not on regex). // Likewise, it MUST happen in a transaction with the later DS delete, so they aren't deleted if the DS delete fails. @@ -1438,7 +1419,7 @@ func (ds *TODeliveryService) Delete() (error, error, int) { paramConfigFilePrefixes := []string{"hdr_rw_", "hdr_rw_mid_", "regex_remap_", "cacheurl_"} configFiles := []string{} for _, prefix := range paramConfigFilePrefixes { - configFiles = append(configFiles, prefix+ds.XMLID+".config") + configFiles = append(configFiles, prefix+*ds.XMLID+".config") } if _, err := ds.ReqInfo.Tx.Tx.Exec(`DELETE FROM parameter WHERE name = 'location' AND config_file = ANY($1)`, pq.Array(configFiles)); err != nil { @@ -1591,6 +1572,8 @@ func Validate(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { "regionalGeoBlocking": validation.Validate(ds.RegionalGeoBlocking, validation.NotNil), "remapText": validation.Validate(ds.RemapText, noLineBreaks), "routingName": validation.Validate(ds.RoutingName, isDNSName, noPeriods, validation.Length(1, 48)), + "typeId": validation.Validate(ds.TypeID, validation.Required, validation.Min(1)), + "xmlId": validation.Validate(ds.XMLID, validation.Required, noSpaces, noPeriods, validation.Length(1, 48)), "tlsVersions": validation.Validate(ds.TLSVersions, validation.By( func(value interface{}) error { vers, ok := value.([]string) @@ -1610,8 +1593,6 @@ func Validate(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { return nil }, )), - "typeId": validation.Validate(ds.TypeID, validation.Required, validation.Min(1)), - "xmlId": validation.Validate(ds.XMLID, validation.Required, noSpaces, noPeriods, validation.Length(1, 48)), }) if err := validateTopologyFields(ds); err != nil { errs = append(errs, err) @@ -1673,7 +1654,7 @@ func validateTypeFields(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { latitudeErr := "Must be a floating point number within the range +-90" longitudeErr := "Must be a floating point number within the range +-180" - typeName, err := tc.ValidateTypeID(tx, &ds.TypeID, "deliveryservice") + typeName, err := tc.ValidateTypeID(tx, ds.TypeID, "deliveryservice") if err != nil { return err } @@ -1690,7 +1671,7 @@ func validateTypeFields(tx *sql.Tx, ds *tc.DeliveryServiceV4) error { "initialDispersion": validation.Validate(ds.InitialDispersion, validation.By(requiredIfMatchesTypeName([]string{HTTPRegexType}, typeName)), validation.By(tovalidate.IsGreaterThanZero)), - "ipv6RoutingEnabled": validation.Validate(&ds.IPV6RoutingEnabled, + "ipv6RoutingEnabled": validation.Validate(ds.IPV6RoutingEnabled, validation.By(requiredIfMatchesTypeName([]string{SteeringRegexType, DNSRegexType, HTTPRegexType}, typeName))), "missLat": validation.Validate(ds.MissLat, validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName)), @@ -1812,7 +1793,7 @@ func updatePrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi count := 0 q := `SELECT count(*) FROM origin WHERE deliveryservice = $1 AND is_primary` if err := tx.QueryRow(q, *ds.ID).Scan(&count); err != nil { - return fmt.Errorf("querying existing primary origin for ds %s: %w", ds.XMLID, err) + return fmt.Errorf("querying existing primary origin for ds %s: %w", *ds.XMLID, err) } if ds.OrgServerFQDN == nil || *ds.OrgServerFQDN == "" { @@ -1820,9 +1801,9 @@ func updatePrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi // the update is removing the existing orgServerFQDN, so the existing row needs to be deleted q = `DELETE FROM origin WHERE deliveryservice = $1 AND is_primary` if _, err := tx.Exec(q, *ds.ID); err != nil { - return fmt.Errorf("deleting primary origin for ds %s: %w", ds.XMLID, err) + return fmt.Errorf("deleting primary origin for ds %s: %w", *ds.XMLID, err) } - api.CreateChangeLogRawTx(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Deleted primary origin", user, tx) + api.CreateChangeLogRawTx(api.ApiChange, "DS: "+*ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Deleted primary origin", user, tx) } return nil } @@ -1840,10 +1821,10 @@ func updatePrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi name := "" q = `UPDATE origin SET protocol = $1, fqdn = $2, port = $3 WHERE is_primary AND deliveryservice = $4 RETURNING name` if err := tx.QueryRow(q, protocol, fqdn, port, *ds.ID).Scan(&name); err != nil { - return fmt.Errorf("update primary origin for ds %s from '%s': %w", ds.XMLID, *ds.OrgServerFQDN, err) + return fmt.Errorf("update primary origin for ds %s from '%s': %w", *ds.XMLID, *ds.OrgServerFQDN, err) } - api.CreateChangeLogRawTx(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Updated primary origin: "+name, user, tx) + api.CreateChangeLogRawTx(api.ApiChange, "DS: "+*ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Updated primary origin: "+name, user, tx) return nil } @@ -1864,7 +1845,7 @@ func createPrimaryOrigin(tx *sql.Tx, user *auth.CurrentUser, ds tc.DeliveryServi return fmt.Errorf("insert origin from '%s': %s", *ds.OrgServerFQDN, err.Error()) } - api.CreateChangeLogRawTx(api.ApiChange, "DS: "+ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Created primary origin id: "+strconv.Itoa(originID), user, tx) + api.CreateChangeLogRawTx(api.ApiChange, "DS: "+*ds.XMLID+", ID: "+strconv.Itoa(*ds.ID)+", ACTION: Created primary origin id: "+strconv.Itoa(originID), user, tx) return nil } @@ -1984,8 +1965,10 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s } } - dsCDNDomains[ds.XMLID] = cdnDomain - ds.DeepCachingType = tc.DeepCachingTypeFromString(string(ds.DeepCachingType)) + dsCDNDomains[*ds.XMLID] = cdnDomain + if ds.DeepCachingType != nil { + *ds.DeepCachingType = tc.DeepCachingTypeFromString(string(*ds.DeepCachingType)) + } ds.Signed = ds.SigningAlgorithm != nil && *ds.SigningAlgorithm == tc.SigningAlgorithmURLSig @@ -1998,7 +1981,7 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s dsNames := make([]string, len(dses), len(dses)) for i, ds := range dses { - dsNames[i] = ds.XMLID + dsNames[i] = *ds.XMLID } matchLists, err := GetDeliveryServicesMatchLists(dsNames, tx.Tx) @@ -2006,12 +1989,12 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s return nil, nil, errors.New("getting delivery service matchlists: " + err.Error()), http.StatusInternalServerError } for i, ds := range dses { - matchList, ok := matchLists[ds.XMLID] + matchList, ok := matchLists[*ds.XMLID] if !ok { continue } ds.MatchList = matchList - ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *ds.Type, ds.RoutingName, ds.MatchList, dsCDNDomains[ds.XMLID]) + ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *ds.Type, *ds.RoutingName, ds.MatchList, dsCDNDomains[*ds.XMLID]) dses[i] = ds } @@ -2038,7 +2021,7 @@ func getCDNNameDomainDNSSecEnabled(dsID int, tx *sql.Tx) (string, string, bool, return cdnName, cdnDomain, dnssecEnabled, nil } -// makeExampleURLs creates the example URLs for a delivery service. The dsProtocol may be nil, if the delivery service type doesn't have a protocol (e.g. ANY_MAP). +// MakeExampleURLs creates the example URLs for a delivery service. The dsProtocol may be nil, if the delivery service type doesn't have a protocol (e.g. ANY_MAP). func MakeExampleURLs(protocol *int, dsType tc.DSType, routingName string, matchList []tc.DeliveryServiceMatch, cdnDomain string) []string { examples := []string{} scheme := "" @@ -2275,16 +2258,19 @@ func deleteLocationParam(tx *sql.Tx, configFile string) error { return nil } -// getTenantID returns the tenant Id of the given delivery service. Note it may return a nil id and nil error, if the tenant ID in the database is nil. +// getTenantID returns the tenant Id of the given delivery service. +// Note it may return a nil id and nil error, if the tenant ID in the database +// is nil. +// This will panic if the transaction is nil. func getTenantID(tx *sql.Tx, ds *tc.DeliveryServiceV4) (*int, error) { - if ds == nil { - return nil, errors.New("delivery service was nil") + if ds == nil || (ds.ID == nil && ds.XMLID == nil) { + return nil, errors.New("delivery service was nil, or had nil identifiers (ID and XMLID)") } if ds.ID != nil { existingID, _, err := getDSTenantIDByID(tx, *ds.ID) // ignore exists return - if the DS is new, we only need to check the user input tenant return existingID, err } - existingID, _, err := getDSTenantIDByName(tx, tc.DeliveryServiceName(ds.XMLID)) // ignore exists return - if the DS is new, we only need to check the user input tenant + existingID, _, err := getDSTenantIDByName(tx, tc.DeliveryServiceName(*ds.XMLID)) // ignore exists return - if the DS is new, we only need to check the user input tenant return existingID, err } @@ -2296,7 +2282,10 @@ func isTenantAuthorized(inf *api.APIInfo, ds *tc.DeliveryServiceV4) (bool, error if err != nil { return false, errors.New("getting tenant ID: " + err.Error()) } - if existingID != nil { + if ds.TenantID == nil { + ds.TenantID = existingID + } + if existingID != nil && existingID != ds.TenantID { userAuthorizedForExistingDSTenant, err := tenant.IsResourceAuthorizedToUserTx(*existingID, user, tx) if err != nil { return false, errors.New("checking authorization for existing DS ID: " + err.Error()) @@ -2305,8 +2294,8 @@ func isTenantAuthorized(inf *api.APIInfo, ds *tc.DeliveryServiceV4) (bool, error return false, nil } } - if ds.TenantID != 0 { - userAuthorizedForNewDSTenant, err := tenant.IsResourceAuthorizedToUserTx(ds.TenantID, user, tx) + if ds.TenantID != nil { + userAuthorizedForNewDSTenant, err := tenant.IsResourceAuthorizedToUserTx(*ds.TenantID, user, tx) if err != nil { return false, errors.New("checking authorization for new DS ID: " + err.Error()) } @@ -2383,8 +2372,11 @@ func sanitize(ds *tc.DeliveryServiceV4) { &ds.InnerHeaderRewrite, &ds.LastHeaderRewrite, ) - if ds.RoutingName == "" { - ds.RoutingName = tc.DefaultRoutingName + if ds.RoutingName == nil || *ds.RoutingName == "" { + ds.RoutingName = util.StrPtr(tc.DefaultRoutingName) + } + if ds.AnonymousBlockingEnabled == nil { + ds.AnonymousBlockingEnabled = util.BoolPtr(false) } signedAlgorithm := tc.SigningAlgorithmURLSig if ds.Signed && (ds.SigningAlgorithm == nil || *ds.SigningAlgorithm == "") { @@ -2396,7 +2388,11 @@ func sanitize(ds *tc.DeliveryServiceV4) { if ds.MaxOriginConnections == nil || *ds.MaxOriginConnections < 0 { ds.MaxOriginConnections = util.IntPtr(0) } - ds.DeepCachingType = tc.DeepCachingTypeFromString(string(ds.DeepCachingType)) + if ds.DeepCachingType == nil { + s := tc.DeepCachingType("") + ds.DeepCachingType = &s + } + *ds.DeepCachingType = tc.DeepCachingTypeFromString(string(*ds.DeepCachingType)) if ds.MaxRequestHeaderBytes == nil { ds.MaxRequestHeaderBytes = util.IntPtr(tc.DefaultMaxRequestHeaderBytes) } diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go index e01de60c59..4c33da6d33 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go @@ -309,7 +309,11 @@ func Get(w http.ResponseWriter, r *http.Request) { // DeliveryService's Tenant, as appropriate to the change type. func isTenantAuthorized(dsr tc.DeliveryServiceRequestV40, inf *api.APIInfo) (bool, error) { if dsr.Requested != nil && (dsr.ChangeType == tc.DSRChangeTypeUpdate || dsr.ChangeType == tc.DSRChangeTypeCreate) { - ok, err := tenant.IsResourceAuthorizedToUserTx(dsr.Requested.TenantID, inf.User, inf.Tx.Tx) + if dsr.Requested.TenantID == nil { + log.Debugf("requested.tenantID is nil") + return false, errors.New("requested.tenantID is nil") + } + ok, err := tenant.IsResourceAuthorizedToUserTx(*dsr.Requested.TenantID, inf.User, inf.Tx.Tx) if err != nil { err = fmt.Errorf("requested: %v", err) } @@ -324,7 +328,11 @@ func isTenantAuthorized(dsr tc.DeliveryServiceRequestV40, inf *api.APIInfo) (boo return true, nil } - ok, err := tenant.IsResourceAuthorizedToUserTx(ds.TenantID, inf.User, inf.Tx.Tx) + if ds.TenantID == nil { + log.Debugf("original.tenantID is nil") + return false, errors.New("original.tenantID is nil") + } + ok, err := tenant.IsResourceAuthorizedToUserTx(*ds.TenantID, inf.User, inf.Tx.Tx) if err != nil { err = fmt.Errorf("original: %v", err) } diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go index 359693faf5..8bf4dc604e 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/validate.go @@ -56,7 +56,7 @@ func validateLegacy(dsr tc.DeliveryServiceRequestNullable, tx *sql.Tx) error { } toStatus, ok := s.(*tc.RequestStatus) if !ok { - return fmt.Errorf("Expected *tc.RequestStatus type, got %T", s) + return fmt.Errorf("expected *tc.RequestStatus type, got %T", s) } return fromStatus.ValidTransition(*toStatus) } @@ -121,7 +121,7 @@ func validateV4(dsr tc.DeliveryServiceRequestV40, tx *sql.Tx) (error, error) { } err := deliveryservice.Validate(tx, ds) if err == nil { - dsr.XMLID = ds.XMLID + dsr.XMLID = *ds.XMLID } return err }, diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/safe.go b/traffic_ops/traffic_ops_golang/deliveryservice/safe.go index b050198ba5..616d793a77 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/safe.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/safe.go @@ -160,7 +160,7 @@ func UpdateSafe(w http.ResponseWriter, r *http.Request) { } } - api.CreateChangeLogRawTx(api.ApiChange, fmt.Sprintf("DS: %s, ID: %d, ACTION: Updated safe fields", ds.XMLID, *ds.ID), inf.User, tx) + api.CreateChangeLogRawTx(api.ApiChange, fmt.Sprintf("DS: %s, ID: %d, ACTION: Updated safe fields", *ds.XMLID, *ds.ID), inf.User, tx) } // updateDSSafe updates the given delivery service in the database. Returns whether the DS existed, and any error. diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go b/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go index 16c5fe89da..aba4fef756 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/servers/delete.go @@ -131,14 +131,27 @@ func delete(w http.ResponseWriter, r *http.Request, deprecated bool) { } ds := dses[0] - if ds.Active { + if ds.Active == nil { + errCode = http.StatusInternalServerError + sysErr = fmt.Errorf("Delivery Service #%d had nil Active", dsID) + api.HandleErrOptionalDeprecation(w, r, tx, errCode, nil, sysErr, deprecated, &alt) + return + } + + if *ds.Active { errCode, userErr, sysErr = checkLastServer(dsID, serverID, tx) if userErr != nil || sysErr != nil { api.HandleErrOptionalDeprecation(w, r, inf.Tx.Tx, errCode, userErr, sysErr, deprecated, &alt) return } } - dsName := ds.XMLID + if ds.XMLID == nil { + errCode = http.StatusInternalServerError + sysErr = fmt.Errorf("Delivery Service #%d had nil XMLID", dsID) + api.HandleErrOptionalDeprecation(w, r, tx, errCode, nil, sysErr, deprecated, &alt) + return + } + dsName := *ds.XMLID serverName, exists, err := dbhelpers.GetServerNameFromID(tx, serverID) if err != nil { diff --git a/traffic_ops/v4-client/deliveryservice.go b/traffic_ops/v4-client/deliveryservice.go index d4af55655d..7976311d41 100644 --- a/traffic_ops/v4-client/deliveryservice.go +++ b/traffic_ops/v4-client/deliveryservice.go @@ -134,7 +134,7 @@ func (to *Session) GetDeliveryServices(opts RequestOptions) (tc.DeliveryServices func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOptions) (tc.DeliveryServicesResponseV4, toclientlib.ReqInf, error) { var reqInf toclientlib.ReqInf var resp tc.DeliveryServicesResponseV4 - if ds.TypeID <= 0 && ds.Type != nil { + if ds.TypeID == nil && ds.Type != nil { typeOpts := NewRequestOptions() typeOpts.QueryParameters.Set("name", ds.Type.String()) ty, _, err := to.GetTypes(typeOpts) @@ -144,10 +144,10 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp if len(ty.Response) == 0 { return resp, reqInf, fmt.Errorf("no Type named '%s'", ds.Type) } - ds.TypeID = ty.Response[0].ID + ds.TypeID = &ty.Response[0].ID } - if ds.CDNID <= 0 && ds.CDNName != nil { + if ds.CDNID == nil && ds.CDNName != nil { cdnOpts := NewRequestOptions() cdnOpts.QueryParameters.Set("name", *ds.CDNName) cdns, _, err := to.GetCDNs(cdnOpts) @@ -158,7 +158,7 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp if len(cdns.Response) == 0 { return resp, reqInf, fmt.Errorf("no CDN named '%s'", *ds.CDNName) } - ds.CDNID = cdns.Response[0].ID + ds.CDNID = &cdns.Response[0].ID } if ds.ProfileID == nil && ds.ProfileName != nil { @@ -174,7 +174,7 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp ds.ProfileID = &profiles.Response[0].ID } - if ds.TenantID <= 0 && ds.Tenant != nil { + if ds.TenantID == nil && ds.Tenant != nil { tenantOpts := NewRequestOptions() tenantOpts.QueryParameters.Set("name", *ds.Tenant) ten, _, err := to.GetTenants(tenantOpts) @@ -184,7 +184,7 @@ func (to *Session) CreateDeliveryService(ds tc.DeliveryServiceV4, opts RequestOp if len(ten.Response) == 0 { return resp, reqInf, fmt.Errorf("no Tenant named '%s'", *ds.Tenant) } - ds.TenantID = ten.Response[0].ID + ds.TenantID = &ten.Response[0].ID } reqInf, err := to.post(apiDeliveryServices, RequestOptions{Header: opts.Header}, ds, &resp) diff --git a/traffic_ops/v4-client/deliveryservice_requests.go b/traffic_ops/v4-client/deliveryservice_requests.go index ae2ee6f357..89e59575d0 100644 --- a/traffic_ops/v4-client/deliveryservice_requests.go +++ b/traffic_ops/v4-client/deliveryservice_requests.go @@ -65,24 +65,24 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequestV4, ds = dsr.Requested } - if ds.TypeID <= 0 && ds.Type.String() != "" { + if ds.TypeID == nil && ds.Type.String() != "" { typeOpts := NewRequestOptions() typeOpts.QueryParameters.Set("name", ds.Type.String()) ty, reqInf, err := to.GetTypes(typeOpts) if err != nil || len(ty.Response) == 0 { return resp, reqInf, errors.New("no type named " + ds.Type.String()) } - ds.TypeID = ty.Response[0].ID + ds.TypeID = &ty.Response[0].ID } - if ds.CDNID <= 0 && ds.CDNName != nil { + if ds.CDNID == nil && ds.CDNName != nil { cdnOpts := NewRequestOptions() cdnOpts.QueryParameters.Set("name", *ds.CDNName) cdns, reqInf, err := to.GetCDNs(cdnOpts) if err != nil || len(cdns.Response) == 0 { return resp, reqInf, fmt.Errorf("no CDN named '%s'", *ds.CDNName) } - ds.CDNID = cdns.Response[0].ID + ds.CDNID = &cdns.Response[0].ID } if ds.ProfileID == nil && ds.ProfileName != nil { @@ -95,14 +95,14 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequestV4, ds.ProfileID = &profiles.Response[0].ID } - if ds.TenantID <= 0 && ds.Tenant != nil { + if ds.TenantID == nil && ds.Tenant != nil { tenantOpts := NewRequestOptions() tenantOpts.QueryParameters.Set("name", *ds.Tenant) ten, reqInf, err := to.GetTenants(tenantOpts) if err != nil || len(ten.Response) == 0 { return resp, reqInf, fmt.Errorf("no Tenant named '%s'", *ds.Tenant) } - ds.TenantID = ten.Response[0].ID + ds.TenantID = &ten.Response[0].ID } reqInf, err := to.post(apiDSRequests, opts, dsr, &resp) From 69c8862a775fc3cc1b4fb04c8a58912b7b91b6ed Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Fri, 11 Jun 2021 11:26:07 -0600 Subject: [PATCH 24/34] Change version checking to proper upgrade to preserve existing pattern --- .../deliveryservice/deliveryservices.go | 60 ++++++++++++++++--- .../deliveryservice/deliveryservices_test.go | 38 ++++++++++++ 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 44414ace26..3a4db87755 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -110,6 +110,42 @@ func (ds *TODeliveryService) IsTenantAuthorized(user *auth.CurrentUser) (bool, e return isTenantAuthorized(ds.ReqInfo, &ds.DeliveryServiceV4) } +const getTLSVersionsQuery = ` +SELECT tls_version +FROM public.deliveryservice_tls_version +WHERE deliveryservice = $1 +ORDER BY tls_version +` + +// GetDSTLSVersions retrieves the TLS versions explicitly supported by a +// Delivery Service identified by dsID. This will panic if handed a nil +// transaction. +func GetDSTLSVersions(dsID int, tx *sql.Tx) ([]string, error) { + rows, err := tx.Query(getTLSVersionsQuery, dsID) + if err != nil { + return nil, fmt.Errorf("querying: %w", err) + } + defer func() { + if err := rows.Close(); err != nil { + log.Errorf("closing TLS versions rows: %v", err) + } + }() + + var vers []string + for rows.Next() { + var ver string + if err = rows.Scan(&ver); err != nil { + return nil, fmt.Errorf("scanning: %w", err) + } + vers = append(vers, ver) + } + err = rows.Err() + if err != nil { + err = fmt.Errorf("iteration error: %w", err) + } + return vers, err +} + func CreateV12(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) if userErr != nil || sysErr != nil { @@ -585,13 +621,10 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t } ds.Type = &dsType - // Don't touch TLSVersions if using old API versions - if inf.Version != nil && inf.Version.Major >= 4 { - if len(ds.TLSVersions) < 1 { - ds.TLSVersions = nil - } else if err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("creating TLS versions for new Delivery Service: %w", err) - } + if len(ds.TLSVersions) < 1 { + ds.TLSVersions = nil + } else if err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx); err != nil { + return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("creating TLS versions for new Delivery Service: %w", err) } if err := createDefaultRegex(tx, *ds.ID, *ds.XMLID); err != nil { @@ -1041,12 +1074,23 @@ WHERE return nil, alerts, status, userErr, sysErr } func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 *tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, tc.Alerts, int, error, error) { + var alerts tc.Alerts + dsNull := tc.DeliveryServiceNullableV30(*dsV31) ds := dsNull.UpgradeToV4() dsV40 := ds + if dsV40.ID == nil { + return nil, alerts, http.StatusInternalServerError, nil, errors.New("cannot update a Delivery Service with nil ID") + } + tx := inf.Tx.Tx + var sysErr error + if dsV40.TLSVersions, sysErr = GetDSTLSVersions(*dsV40.ID, tx); sysErr != nil { + return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("getting TLS versions for DS #%d in API version < 4.0: %w", *dsV40.ID, sysErr) + } + res, alerts, status, usrErr, sysErr := updateV40(w, r, inf, &dsV40, false) - if res == nil { + if res == nil || usrErr != nil || sysErr != nil { return nil, alerts, status, usrErr, sysErr } ds = *res diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go index cb0adefd67..9f32afb4e4 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go @@ -126,6 +126,44 @@ func TestGetDeliveryServicesMatchLists(t *testing.T) { } } +func TestGetDSTLSVersions(t *testing.T) { + mockDB, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Unexpected error opening a stub database connection: %v", err) + } + defer func() { + if err := mockDB.Close(); err != nil { + t.Errorf("Failed to close database: %v", err) + } + }() + + db := sqlx.NewDb(mockDB, "sqlmock") + defer func() { + if err := db.Close(); err != nil { + t.Errorf("Failed to close sqlx DB handle: %v", err) + } + }() + + rows := sqlmock.NewRows([]string{"tls_version"}) + expected := []string{"1.0", "1.1", "1.2", "1.3"} + rows.AddRow(expected[0]) + rows.AddRow(expected[1]) + rows.AddRow(expected[2]) + rows.AddRow(expected[3]) + + mock.ExpectBegin() + mock.ExpectQuery("SELECT tls_version").WillReturnRows(rows) + + vers, err := GetDSTLSVersions(0, db.MustBegin().Tx) + if err != nil { + t.Errorf("Unexpected error getting DS TLS Versions: %v", err) + } else if len(vers) != 4 { + t.Errorf("Expected to get 4 TLS versions, got: %d", len(vers)) + } else if !reflect.DeepEqual(expected, vers) { + t.Errorf("Incorrect TLS versions returned, expected: %v - actual: %v", expected, vers) + } +} + func TestMakeExampleURLs(t *testing.T) { expected := []string{ `http://routing-name.ds-name.domain-name.invalid`, From f265cf602bf62d173a704cfd400b08b21268266f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 15 Jun 2021 07:44:39 -0600 Subject: [PATCH 25/34] Rename function to make its purpose clear --- lib/go-tc/deliveryservices.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go index 34d2196af1..86c692c81d 100644 --- a/lib/go-tc/deliveryservices.go +++ b/lib/go-tc/deliveryservices.go @@ -494,7 +494,7 @@ const ( TLSVersion13 = "1.3" ) -func newerDisallowedMessage(old string, newer []string) string { +func newerTLSVersionsDisallowedMessage(old string, newer []string) string { l := len(newer) if l < 1 { return "" @@ -574,7 +574,7 @@ func TLSVersionsAlerts(vers []string) Alerts { if !found[TLSVersion13] { newerDisallowed = append(newerDisallowed, TLSVersion13) } - msg := newerDisallowedMessage(TLSVersion10, newerDisallowed) + msg := newerTLSVersionsDisallowedMessage(TLSVersion10, newerDisallowed) if msg != "" { messages = append(messages, msg) } @@ -586,7 +586,7 @@ func TLSVersionsAlerts(vers []string) Alerts { if !found[TLSVersion13] { newerDisallowed = append(newerDisallowed, TLSVersion13) } - msg := newerDisallowedMessage(TLSVersion11, newerDisallowed) + msg := newerTLSVersionsDisallowedMessage(TLSVersion11, newerDisallowed) if msg != "" { messages = append(messages, msg) } @@ -595,7 +595,7 @@ func TLSVersionsAlerts(vers []string) Alerts { if !found[TLSVersion13] { newerDisallowed = append(newerDisallowed, TLSVersion13) } - msg := newerDisallowedMessage(TLSVersion12, newerDisallowed) + msg := newerTLSVersionsDisallowedMessage(TLSVersion12, newerDisallowed) if msg != "" { messages = append(messages, msg) } From 4a60946068082ecd44a0b981ba14521b56e8bde5 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 15 Jun 2021 07:48:17 -0600 Subject: [PATCH 26/34] Move comment into GoDoc where it's more useful --- traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go index ac42b121ec..575cd3ba70 100644 --- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go +++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go @@ -908,8 +908,10 @@ func TopologyExists(tx *sql.Tx, name string) (bool, error) { return count > 0, err } -// CheckTopology returns an error if the given Topology does not exist or if one of the Topology's Cache Groups is -// empty with respect to the Delivery Service's CDN. +// CheckTopology returns an error if the given Topology does not exist or if +// one of the Topology's Cache Groups is empty with respect to the Delivery +// Service's CDN. Note that this can panic if ds does not have a properly set +// CDNID. func CheckTopology(tx *sqlx.Tx, ds tc.DeliveryServiceV4) (int, error, error) { statusCode, userErr, sysErr := http.StatusOK, error(nil), error(nil) @@ -925,7 +927,6 @@ func CheckTopology(tx *sqlx.Tx, ds tc.DeliveryServiceV4) (int, error, error) { return http.StatusBadRequest, fmt.Errorf("no such Topology '%s'", *ds.Topology), nil } - // note that this segfaults if the ds doesn't have a properly set CDNID if err = topology_validation.CheckForEmptyCacheGroups(tx, cacheGroupIDs, []int{*ds.CDNID}, true, []int{}); err != nil { return http.StatusBadRequest, fmt.Errorf("empty cachegroups in Topology %s found for CDN %d: %w", *ds.Topology, *ds.CDNID, err), nil } From 40868041e706d56e9269dd1d233b5fc32082edf8 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 15 Jun 2021 08:11:00 -0600 Subject: [PATCH 27/34] Use Exec for queries that don't return rows --- .../deliveryservice/deliveryservices.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 3a4db87755..6c9f6a41cb 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -385,8 +385,8 @@ ON CONFLICT DO NOTHING ` func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { - err := tx.QueryRow(`DELETE FROM public.deliveryservice_tls_version WHERE deliveryservice = $1`, dsid).Scan() - if err != nil && !errors.Is(err, sql.ErrNoRows) { + _, err := tx.Exec(`DELETE FROM public.deliveryservice_tls_version WHERE deliveryservice = $1`, dsid) + if err != nil { return fmt.Errorf("cleaning up existing TLS version for DS #%d: %w", dsid, err) } @@ -394,18 +394,10 @@ func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { return nil } - rows, err := tx.Query(insertTLSVersionsQuery, dsid, pq.Array(versions)) + _, err = tx.Exec(insertTLSVersionsQuery, dsid, pq.Array(versions)) if err != nil { return fmt.Errorf("inserting new TLS versions: %w", err) } - err = rows.Close() - if err != nil { - log.Errorln("closing TLS versions insert rows: ", err.Error()) - } - if err = rows.Err(); err != nil { - log.Errorln("an error occurred at some point in the TLS insertion query: ", err.Error()) - } - return nil } From d3c598e0f0e1311034995625d0686b7a9d5a9c67 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 15 Jun 2021 08:52:18 -0600 Subject: [PATCH 28/34] Consolidate TLS Versions warnings into a single function That function is now a method of a Delivery Service, which means the call signatures of various functions in the github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice package no longer need to be changed. --- lib/go-tc/deliveryservices.go | 28 +- lib/go-tc/deliveryservices_test.go | 104 +++--- .../deliveryservice/deliveryservices.go | 351 ++++++++---------- 3 files changed, 236 insertions(+), 247 deletions(-) diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go index 86c692c81d..f178b96aff 100644 --- a/lib/go-tc/deliveryservices.go +++ b/lib/go-tc/deliveryservices.go @@ -528,18 +528,24 @@ func newerTLSVersionsDisallowedMessage(old string, newer []string) string { return msg.String() } -// TLSVersionsAlerts generates warning-level alerts for the given TLS versions -// array. It will warn if newer versions are disallowed while older, less -// secure versions are allowed, or if there are unrecognized versions present. +// TLSVersionsAlerts generates warning-level alerts for the Delivery Service's +// TLS versions array. It will warn if newer versions are disallowed while +// older, less secure versions are allowed, if there are unrecognized versions +// present, if the Delivery Service's Protocol does not make use of TLS +// Versions, and whenever TLSVersions are explicitly set at all. // -// This does NOT verify that the passed TLS versions are _valid_, it ONLY -// creates warnings based on conditions that are possibly detrimental to CDN -// operation, but can, in fact, work. -func TLSVersionsAlerts(vers []string) Alerts { - if len(vers) < 1 { +// This does NOT verify that the Delivery Service's TLS versions are _valid_, +// it ONLY creates warnings based on conditions that are possibly detrimental +// to CDN operation, but can, in fact, work. +func (ds DeliveryServiceV4) TLSVersionsAlerts() Alerts { + vers := ds.TLSVersions + messages := []string{} + + if len(vers) > 0 { + messages = append(messages, "setting TLS Versions that are explicitly supported may break older clients that can't use the specified versions") + } else { return Alerts{Alerts: []Alert{}} } - messages := []string{} found := map[string]bool{ TLSVersion10: false, @@ -601,6 +607,10 @@ func TLSVersionsAlerts(vers []string) Alerts { } } + if ds.Protocol != nil && *ds.Protocol == DSProtocolHTTP { + messages = append(messages, "tlsVersions has no effect on Delivery Services with Protocol '0' (HTTP_ONLY)") + } + return CreateAlerts(WarnLevel, messages...) } diff --git a/lib/go-tc/deliveryservices_test.go b/lib/go-tc/deliveryservices_test.go index 2d32588495..2f2dca401a 100644 --- a/lib/go-tc/deliveryservices_test.go +++ b/lib/go-tc/deliveryservices_test.go @@ -705,105 +705,122 @@ func containsWarning(a Alerts, expected string) func(*testing.T) { } } +const nonNilTLSVersionsWarningMessage = "setting TLS Versions that are explicitly supported may break older clients that can't use the specified versions" + func TestTLSVersionsAlerts(t *testing.T) { - var vers []string - alerts := TLSVersionsAlerts(vers) + var ds DeliveryServiceV40 + alerts := ds.TLSVersionsAlerts() if alerts.HasAlerts() { t.Errorf("nil versions should not produce any warnings, but these were generated: %v", alerts.Alerts) } - vers = make([]string, 0, 3) - alerts = TLSVersionsAlerts(vers) + ds.TLSVersions = make([]string, 0, 3) + alerts = ds.TLSVersionsAlerts() if alerts.HasAlerts() { t.Errorf("empty versions should not produce any warnings, but these were generated: %v", alerts.Alerts) } + ds.Protocol = new(int) + *ds.Protocol = 0 expected := "old TLS version 1.0 is allowed, but newer versions 1.1, 1.2, and 1.3 are disallowed; this configuration may be insecure" - vers = append(vers, TLSVersion10) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 1 { - t.Errorf("expected allowing only TLS v1.0 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion10) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 3 { + t.Errorf("expected allowing only TLS v1.0 to generate exactly three warnings, got %d: %v", len(alerts.Alerts), alerts) } else { t.Run("only TLS version 1.0 allowed - returns warnings", expectOnlyWarnings(alerts)) t.Run("only TLS version 1.0 allowed - has expected warning", containsWarning(alerts, expected)) + expected = "tlsVersions has no effect on Delivery Services with Protocol '0' (HTTP_ONLY)" + t.Run("only TLS version 1.0 allowed - has warning about Protocol '0'", containsWarning(alerts, expected)) + t.Run("only TLS version 1.0 allowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } + ds.Protocol = nil expected = "old TLS version 1.0 is allowed, but newer versions 1.1, and 1.3 are disallowed; this configuration may be insecure" - vers = append(vers, TLSVersion12) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 1 { - t.Errorf("expected allowing only TLS v1.0 and 1.2 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion12) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 2 { + t.Errorf("expected allowing only TLS v1.0 and 1.2 to generate exactly two warnings, got %d: %v", len(alerts.Alerts), alerts) } else { t.Run("only TLS versions 1.0 and 1.2 allowed - returns warnings", expectOnlyWarnings(alerts)) t.Run("only TLS versions 1.0 and 1.2 allowed - has expected warning", containsWarning(alerts, expected)) + t.Run("only TLS versions 1.0 and 1.2 allowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } expected = "old TLS version 1.0 is allowed, but newer version 1.3 is disallowed; this configuration may be insecure" - vers = append(vers, TLSVersion11) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 1 { - t.Errorf("expected disallowing only TLS v1.3 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion11) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 2 { + t.Errorf("expected disallowing only TLS v1.3 to generate exactly two warnings, got %d: %v", len(alerts.Alerts), alerts) } else { t.Run("only TLS version 1.3 disallowed - returns warnings", expectOnlyWarnings(alerts)) t.Run("only TLS version 1.3 disallowed - has expected warning", containsWarning(alerts, expected)) + t.Run("only TLS version 1.3 disallowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } expected = "old TLS version 1.1 is allowed, but newer versions 1.2, and 1.3 are disallowed; this configuration may be insecure" - vers = make([]string, 0, 2) - vers = append(vers, TLSVersion11) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 1 { - t.Errorf("expected allowing only TLS v1.1 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + ds.TLSVersions = make([]string, 0, 2) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion11) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 2 { + t.Errorf("expected allowing only TLS v1.1 to generate exactly two warnings, got %d: %v", len(alerts.Alerts), alerts) } else { t.Run("only TLS version 1.1 allowed - returns warnings", expectOnlyWarnings(alerts)) t.Run("only TLS version 1.1 allowed - has expected warning", containsWarning(alerts, expected)) + t.Run("only TLS version 1.1 allowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } expected = "old TLS version 1.1 is allowed, but newer version 1.3 is disallowed; this configuration may be insecure" - vers = append(vers, TLSVersion12) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 1 { - t.Errorf("expected allowing only TLS v1.1 and 1.2 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion12) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 2 { + t.Errorf("expected allowing only TLS v1.1 and 1.2 to generate exactly two warning, got %d: %v", len(alerts.Alerts), alerts) } else { t.Run("only TLS versions 1.1 and 1.2 allowed - returns warnings", expectOnlyWarnings(alerts)) t.Run("only TLS versions 1.1 and 1.2 allowed - has expected warning", containsWarning(alerts, expected)) + t.Run("only TLS versions 1.1 and 1.2 allowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } expected = "old TLS version 1.2 is allowed, but newer version 1.3 is disallowed; this configuration may be insecure" - vers = make([]string, 0, 4) - vers = append(vers, TLSVersion12) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 1 { - t.Errorf("expected allowing only TLS v1.2 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts) + ds.TLSVersions = make([]string, 0, 4) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion12) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 2 { + t.Errorf("expected allowing only TLS v1.2 to generate exactly two warnings, got %d: %v", len(alerts.Alerts), alerts) } else { t.Run("only TLS version 1.2 allowed - returns warnings", expectOnlyWarnings(alerts)) t.Run("only TLS version 1.2 allowed - has expected warning", containsWarning(alerts, expected)) + t.Run("only TLS version 1.2 allowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } - vers = append(vers, TLSVersion13) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) > 0 { - t.Errorf("Expected allowing TLS versions 1.2 and 1.3 to not generate any warnings, got %d: %v", len(alerts.Alerts), alerts.Alerts) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion13) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 1 { + t.Errorf("Expected allowing TLS versions 1.2 and 1.3 to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts.Alerts) + } else { + t.Run("only TLS versions 1.2 and 1.3 allowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } expected = "unknown TLS version '13.37' - possible typo" - vers = append(vers, "13.37") - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 1 { - t.Errorf("expected allowing an unknown TLS version to generate exactly one warning, got %d: %v", len(alerts.Alerts), alerts.Alerts) + ds.TLSVersions = append(ds.TLSVersions, "13.37") + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 2 { + t.Errorf("expected allowing an unknown TLS version to generate exactly two warnings, got %d: %v", len(alerts.Alerts), alerts.Alerts) } else { t.Run("unknown TLS version allowed - returns warnings", expectOnlyWarnings(alerts)) t.Run("unknown TLS version allowed - has expected warning", containsWarning(alerts, expected)) + t.Run("unknown TLS version allowed - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } - vers = append(vers, TLSVersion10) - alerts = TLSVersionsAlerts(vers) - if len(alerts.Alerts) != 2 { - t.Errorf("expected allowing an unknown TLS version and disallowing only version 1.1 to generate exactly two warnings, got %d: %v", len(alerts.Alerts), alerts.Alerts) + ds.TLSVersions = append(ds.TLSVersions, TLSVersion10) + alerts = ds.TLSVersionsAlerts() + if len(alerts.Alerts) != 3 { + t.Errorf("expected allowing an unknown TLS version and disallowing only version 1.1 to generate exactly three warnings, got %d: %v", len(alerts.Alerts), alerts.Alerts) } else { t.Run("unknown TLS version and disallowed v1.1 - returns warnings", expectOnlyWarnings(alerts)) t.Run("unknown TLS version and disallowed v1.1 - has expected warning", containsWarning(alerts, expected)) expected = "old TLS version 1.0 is allowed, but newer version 1.1 is disallowed; this configuration may be insecure" t.Run("unknown TLS version and disallowed v1.1 - has second expected warning", containsWarning(alerts, expected)) + t.Run("unknown TLS version and disallowed v1.1 - has warning about non-nil tlsVersions", containsWarning(alerts, nonNilTLSVersionsWarningMessage)) } } @@ -818,10 +835,11 @@ func BenchmarkTLSVersionsAlerts(b *testing.B) { versions = append(versions, fmt.Sprintf("%d.%d", major, minor)) } } + ds := DeliveryServiceV4{TLSVersions: versions} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - TLSVersionsAlerts(versions) + ds.TLSVersionsAlerts() } } diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 6c9f6a41cb..0febddb39d 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -160,13 +160,12 @@ func CreateV12(w http.ResponseWriter, r *http.Request) { return } - res, alerts, status, userErr, sysErr := createV12(w, r, inf, ds) + res, status, userErr, sysErr := createV12(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV12{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service creation was successful", []tc.DeliveryServiceNullableV12{*res}) } func CreateV13(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -182,13 +181,12 @@ func CreateV13(w http.ResponseWriter, r *http.Request) { return } - res, alerts, status, userErr, sysErr := createV13(w, r, inf, ds) + res, status, userErr, sysErr := createV13(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV13{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service creation was successful", []tc.DeliveryServiceNullableV13{*res}) } func CreateV14(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -204,13 +202,12 @@ func CreateV14(w http.ResponseWriter, r *http.Request) { return } - res, alerts, status, userErr, sysErr := createV14(w, r, inf, ds) + res, status, userErr, sysErr := createV14(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV14{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service creation was successful", []tc.DeliveryServiceNullableV14{*res}) } // TODO allow users to post names (type, cdn, etc) and get the IDs from the names. This isn't trivial to do in a single query, without dynamically building the entire insert query, and ideally inserting would be one query. But it'd be much more convenient for users. Alternatively, remove IDs from the database entirely and use real candidate keys. @@ -228,13 +225,12 @@ func CreateV15(w http.ResponseWriter, r *http.Request) { return } - res, alerts, status, userErr, sysErr := createV15(w, r, inf, ds) + res, status, userErr, sysErr := createV15(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV15{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service creation was successful", []tc.DeliveryServiceNullableV15{*res}) } func CreateV30(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -250,13 +246,12 @@ func CreateV30(w http.ResponseWriter, r *http.Request) { return } - res, alerts, status, userErr, sysErr := createV30(w, r, inf, ds) + res, status, userErr, sysErr := createV30(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV30{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service creation was successful", []tc.DeliveryServiceV30{*res}) } func CreateV31(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -272,13 +267,12 @@ func CreateV31(w http.ResponseWriter, r *http.Request) { return } - res, alerts, status, userErr, sysErr := createV31(w, r, inf, ds) + res, status, userErr, sysErr := createV31(w, r, inf, ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV31{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service creation was successful", []tc.DeliveryServiceV31{*res}) } func CreateV40(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) @@ -294,63 +288,64 @@ func CreateV40(w http.ResponseWriter, r *http.Request) { return } - res, alerts, status, userErr, sysErr := createV40(w, r, inf, ds, true) + res, status, userErr, sysErr := createV40(w, r, inf, ds, true) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } + alerts := res.TLSVersionsAlerts() alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service creation was successful") w.Header().Set("Location", fmt.Sprintf("/api/4.0/deliveryservices?id=%d", *res.ID)) api.WriteAlertsObj(w, r, http.StatusCreated, alerts, []tc.DeliveryServiceV40{*res}) } -func createV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, tc.Alerts, int, error, error) { +func createV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, int, error, error) { dsV13 := tc.DeliveryServiceNullableV13{DeliveryServiceNullableV12: reqDS} - res, alerts, status, userErr, sysErr := createV13(w, r, inf, dsV13) + res, status, userErr, sysErr := createV13(w, r, inf, dsV13) if res != nil { - return &res.DeliveryServiceNullableV12, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV12, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func createV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, tc.Alerts, int, error, error) { +func createV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, int, error, error) { dsV14 := tc.DeliveryServiceNullableV14{DeliveryServiceNullableV13: reqDS} - res, alerts, status, userErr, sysErr := createV14(w, r, inf, dsV14) + res, status, userErr, sysErr := createV14(w, r, inf, dsV14) if res != nil { - return &res.DeliveryServiceNullableV13, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV13, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func createV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, tc.Alerts, int, error, error) { +func createV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, int, error, error) { dsV15 := tc.DeliveryServiceNullableV15{DeliveryServiceNullableV14: reqDS} - res, alerts, status, userErr, sysErr := createV15(w, r, inf, dsV15) + res, status, userErr, sysErr := createV15(w, r, inf, dsV15) if res != nil { - return &res.DeliveryServiceNullableV14, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV14, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func createV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, tc.Alerts, int, error, error) { +func createV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, int, error, error) { dsV30 := tc.DeliveryServiceV30{DeliveryServiceNullableV15: reqDS} - res, alerts, status, userErr, sysErr := createV30(w, r, inf, dsV30) + res, status, userErr, sysErr := createV30(w, r, inf, dsV30) if res != nil { - return &res.DeliveryServiceNullableV15, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV15, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func createV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, tc.Alerts, int, error, error) { +func createV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, int, error, error) { ds := tc.DeliveryServiceV31{DeliveryServiceV30: dsV30} - res, alerts, status, userErr, sysErr := createV31(w, r, inf, ds) + res, status, userErr, sysErr := createV31(w, r, inf, ds) if res != nil { - return &res.DeliveryServiceV30, alerts, status, userErr, sysErr + return &res.DeliveryServiceV30, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, tc.Alerts, int, error, error) { +func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, int, error, error) { tx := inf.Tx.Tx dsNullable := tc.DeliveryServiceNullableV30(dsV31) ds := dsNullable.UpgradeToV4() - res, alerts, status, userErr, sysErr := createV40(w, r, inf, tc.DeliveryServiceV40(ds), false) + res, status, userErr, sysErr := createV40(w, r, inf, tc.DeliveryServiceV40(ds), false) if res == nil { - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } ds = tc.DeliveryServiceV4(*res) @@ -360,16 +355,16 @@ func createV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 t &ds.ID) if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, alerts, code, usrErr, sysErr + return nil, code, usrErr, sysErr } } if err := EnsureCacheURLParams(tx, *ds.ID, *ds.XMLID, dsV31.CacheURL); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, err + return nil, http.StatusInternalServerError, nil, err } oldRes := tc.DeliveryServiceV31(ds.DowngradeToV3()) - return &oldRes, alerts, status, userErr, sysErr + return &oldRes, status, userErr, sysErr } // 'ON CONFLICT DO NOTHING' should be unnecessary because all data should be @@ -401,41 +396,20 @@ func recreateTLSVersions(versions []string, dsid int, tx *sql.Tx) error { return nil } -// generates warning-level alerts (if any are necessary) for a Delivery Service -// based on its TLS Versions. This will panic if handed a nil transaction, or -// if the given Delivery Service has a nil TypeID. -func generateTLSVersionWarnings(ds tc.DeliveryServiceV4, tx *sql.Tx) tc.Alerts { - alerts := tc.TLSVersionsAlerts(ds.TLSVersions) - - var httpType int - if err := tx.QueryRow(`SELECT id FROM public.type WHERE name = 'HTTP'`).Scan(&httpType); err != nil { - log.Errorln("Failed to get 'HTTP' type: ", err.Error()) - } else if httpType == *ds.TypeID { - if len(ds.TLSVersions) >= 1 { - alerts.AddNewAlert(tc.WarnLevel, "tlsVersions has no effect on 'HTTP' Delivery Services") - } - } else if len(ds.TLSVersions) >= 1 { - alerts.AddNewAlert(tc.WarnLevel, "setting TLS Versions that are explicitly supported may break older clients that can't use the specified versions") - } - - return alerts -} - // create creates the given ds in the database, and returns the DS with its id and other fields created on insert set. On error, the HTTP status code, user error, and system error are returned. The status code SHOULD NOT be used, if both errors are nil. -func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, tc.Alerts, int, error, error) { +func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, int, error, error) { user := inf.User tx := inf.Tx.Tx ds := tc.DeliveryServiceV4(dsV40) - var alerts tc.Alerts err := Validate(tx, &ds) if err != nil { - return nil, alerts, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil + return nil, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil } if authorized, err := isTenantAuthorized(inf, &ds); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) } else if !authorized { - return nil, alerts, http.StatusForbidden, errors.New("not authorized on this tenant"), nil + 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. @@ -445,12 +419,12 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t } if errCode, userErr, sysErr := dbhelpers.CheckTopology(inf.Tx, ds); userErr != nil || sysErr != nil { - return nil, alerts, errCode, userErr, sysErr + return nil, errCode, userErr, sysErr } var resultRows *sql.Rows if omitExtraLongDescFields { if ds.LongDesc1 != nil || ds.LongDesc2 != nil { - return nil, alerts, http.StatusBadRequest, errors.New("the longDesc1 and longDesc2 fields are no longer supported in API 4.0 onwards"), 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, @@ -577,100 +551,97 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, alerts, code, usrErr, sysErr + return nil, code, usrErr, sysErr } defer resultRows.Close() id := 0 var lastUpdated time.Time if !resultRows.Next() { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("no deliveryservice request inserted, no id was returned") + return nil, http.StatusInternalServerError, nil, errors.New("no deliveryservice request inserted, no id was returned") } if err := resultRows.Scan(&id, &lastUpdated); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("could not scan id from insert: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("could not scan id from insert: " + err.Error()) } if resultRows.Next() { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("too many ids returned from deliveryservice request insert") + return nil, http.StatusInternalServerError, nil, errors.New("too many ids returned from deliveryservice request insert") } ds.ID = &id if ds.ID == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing id after insert") + return nil, http.StatusInternalServerError, nil, errors.New("missing id after insert") } if ds.XMLID == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing xml_id after insert") + return nil, http.StatusInternalServerError, nil, errors.New("missing xml_id after insert") } if ds.TypeID == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing type id after insert") + return nil, http.StatusInternalServerError, nil, errors.New("missing type id after insert") } if ds.RoutingName == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing routing name after insert") + return nil, http.StatusInternalServerError, nil, errors.New("missing routing name after insert") } dsType, err := getTypeFromID(*ds.TypeID, tx) if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type: " + err.Error()) } ds.Type = &dsType if len(ds.TLSVersions) < 1 { ds.TLSVersions = nil } else if err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("creating TLS versions for new Delivery Service: %w", err) + 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, alerts, http.StatusInternalServerError, nil, errors.New("creating default regex: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("creating default regex: " + err.Error()) } if _, err := createConsistentHashQueryParams(tx, *ds.ID, ds.ConsistentHashQueryParams); err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, alerts, code, usrErr, sysErr + return nil, code, usrErr, sysErr } matchlists, err := GetDeliveryServicesMatchLists([]string{*ds.XMLID}, tx) if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: " + err.Error()) } if matchlist, ok := matchlists[*ds.XMLID]; !ok { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: not found") + return nil, http.StatusInternalServerError, nil, errors.New("creating DS: reading matchlists: not found") } else { ds.MatchList = matchlist } cdnName, cdnDomain, dnssecEnabled, err := getCDNNameDomainDNSSecEnabled(*ds.ID, tx) if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating DS: getting CDN info: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("creating DS: getting CDN info: " + err.Error()) } ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *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, alerts, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) } if dnssecEnabled && ds.Type.UsesDNSSECKeys() { if !inf.Config.TrafficVaultEnabled { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("cannot create DNSSEC keys for delivery service: Traffic Vault is not configured") + 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, alerts, statusCode, userErr, sysErr + return nil, statusCode, userErr, sysErr } } if err := createPrimaryOrigin(tx, user, ds); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("creating delivery service: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("creating delivery service: " + err.Error()) } 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, alerts, http.StatusInternalServerError, nil, errors.New("error writing to audit log: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("error writing to audit log: " + err.Error()) } - alerts = generateTLSVersionWarnings(ds, tx) - - dsV40 = tc.DeliveryServiceV40(ds) - return &dsV40, alerts, http.StatusOK, nil, nil + return &dsV40, http.StatusOK, nil, nil } func createDefaultRegex(tx *sql.Tx, dsID int, xmlID string) error { @@ -760,13 +731,12 @@ func UpdateV12(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, alerts, status, userErr, sysErr := updateV12(w, r, inf, &ds) + res, status, userErr, sysErr := updateV12(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV12{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service update was successful", []tc.DeliveryServiceNullableV12{*res}) } func UpdateV13(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -785,13 +755,12 @@ func UpdateV13(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, alerts, status, userErr, sysErr := updateV13(w, r, inf, &ds) + res, status, userErr, sysErr := updateV13(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV13{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service update was successful", []tc.DeliveryServiceNullableV13{*res}) } func UpdateV14(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -810,13 +779,12 @@ func UpdateV14(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, alerts, status, userErr, sysErr := updateV14(w, r, inf, &ds) + res, status, userErr, sysErr := updateV14(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV14{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service update was successful", []tc.DeliveryServiceNullableV14{*res}) } func UpdateV15(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -835,13 +803,12 @@ func UpdateV15(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, alerts, status, userErr, sysErr := updateV15(w, r, inf, &ds) + res, status, userErr, sysErr := updateV15(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceNullableV15{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service update was successful", []tc.DeliveryServiceNullableV15{*res}) } func UpdateV30(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -860,13 +827,12 @@ func UpdateV30(w http.ResponseWriter, r *http.Request) { } ds.ID = &id - res, alerts, status, userErr, sysErr := updateV30(w, r, inf, &ds) + res, status, userErr, sysErr := updateV30(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV30{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service update was successful", []tc.DeliveryServiceV30{*res}) } func UpdateV31(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -884,13 +850,12 @@ func UpdateV31(w http.ResponseWriter, r *http.Request) { return } ds.ID = &id - res, alerts, status, userErr, sysErr := updateV31(w, r, inf, &ds) + res, status, userErr, sysErr := updateV31(w, r, inf, &ds) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } - alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") - api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV31{*res}) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Delivery Service update was successful", []tc.DeliveryServiceV31{*res}) } func UpdateV40(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) @@ -908,16 +873,17 @@ func UpdateV40(w http.ResponseWriter, r *http.Request) { return } ds.ID = &id - res, alerts, status, userErr, sysErr := updateV40(w, r, inf, &ds, true) + res, status, userErr, sysErr := updateV40(w, r, inf, &ds, true) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, status, userErr, sysErr) return } + alerts := res.TLSVersionsAlerts() alerts.AddNewAlert(tc.SuccessLevel, "Delivery Service update was successful") api.WriteAlertsObj(w, r, http.StatusOK, alerts, []tc.DeliveryServiceV40{*res}) } -func updateV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, tc.Alerts, int, error, error) { +func updateV12(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV12) (*tc.DeliveryServiceNullableV12, int, error, error) { dsV13 := tc.DeliveryServiceNullableV13{DeliveryServiceNullableV12: *reqDS} // query the DB for existing 1.3 fields in order to "upgrade" this 1.2 request into a 1.3 request query := ` @@ -939,21 +905,21 @@ WHERE &dsV13.TRRequestHeaders, ); err != nil { if err == sql.ErrNoRows { - return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV13.ID), nil + return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV13.ID), nil } - return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV13.ID, err.Error()) + return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV13.ID, err.Error()) } if dsV13.DeepCachingType != nil { *dsV13.DeepCachingType = tc.DeepCachingTypeFromString(string(*dsV13.DeepCachingType)) } - res, alerts, status, userErr, sysErr := updateV13(w, r, inf, &dsV13) + res, status, userErr, sysErr := updateV13(w, r, inf, &dsV13) if res != nil { - return &res.DeliveryServiceNullableV12, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV12, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func updateV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, tc.Alerts, int, error, error) { +func updateV13(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV13) (*tc.DeliveryServiceNullableV13, int, error, error) { dsV14 := tc.DeliveryServiceNullableV14{DeliveryServiceNullableV13: *reqDS} // query the DB for existing 1.4 fields in order to "upgrade" this 1.3 request into a 1.4 request query := ` @@ -973,17 +939,17 @@ WHERE pq.Array(&dsV14.ConsistentHashQueryParams), ); err != nil { if err == sql.ErrNoRows { - return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV14.ID), nil + return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV14.ID), nil } - return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV14.ID, err.Error()) + return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV14.ID, err.Error()) } - res, alerts, status, userErr, sysErr := updateV14(w, r, inf, &dsV14) + res, status, userErr, sysErr := updateV14(w, r, inf, &dsV14) if res != nil { - return &res.DeliveryServiceNullableV13, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV13, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func updateV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, tc.Alerts, int, error, error) { +func updateV14(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV14) (*tc.DeliveryServiceNullableV14, int, error, error) { dsV15 := tc.DeliveryServiceNullableV15{DeliveryServiceNullableV14: *reqDS} // query the DB for existing 1.5 fields in order to "upgrade" this 1.4 request into a 1.5 request query := ` @@ -999,17 +965,17 @@ WHERE &dsV15.RangeSliceBlockSize, ); err != nil { if err == sql.ErrNoRows { - return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV15.ID), nil + return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV15.ID), nil } - return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV15.ID, err.Error()) + return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV15.ID, err.Error()) } - res, alerts, status, userErr, sysErr := updateV15(w, r, inf, &dsV15) + res, status, userErr, sysErr := updateV15(w, r, inf, &dsV15) if res != nil { - return &res.DeliveryServiceNullableV14, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV14, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func updateV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, tc.Alerts, int, error, error) { +func updateV15(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS *tc.DeliveryServiceNullableV15) (*tc.DeliveryServiceNullableV15, int, error, error) { dsV30 := tc.DeliveryServiceV30{DeliveryServiceNullableV15: *reqDS} // query the DB for existing 3.0 fields in order to "upgrade" this 1.5 request into a 3.0 request query := ` @@ -1031,17 +997,17 @@ WHERE &dsV30.ServiceCategory, ); err != nil { if err == sql.ErrNoRows { - return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV30.ID), nil + return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV30.ID), nil } - return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV30.ID, err.Error()) + return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV30.ID, err.Error()) } - res, alerts, status, userErr, sysErr := updateV30(w, r, inf, &dsV30) + res, status, userErr, sysErr := updateV30(w, r, inf, &dsV30) if res != nil { - return &res.DeliveryServiceNullableV15, alerts, status, userErr, sysErr + return &res.DeliveryServiceNullableV15, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func updateV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 *tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, tc.Alerts, int, error, error) { +func updateV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV30 *tc.DeliveryServiceV30) (*tc.DeliveryServiceV30, int, error, error) { dsV31 := tc.DeliveryServiceV31{DeliveryServiceV30: *dsV30} // query the DB for existing 3.1 fields in order to "upgrade" this 3.0 request into a 3.1 request query := ` @@ -1055,35 +1021,33 @@ WHERE &dsV31.MaxRequestHeaderBytes, ); err != nil { if err == sql.ErrNoRows { - return nil, tc.Alerts{}, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV31.ID), nil + return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV31.ID), nil } - return nil, tc.Alerts{}, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV31.ID, err.Error()) + return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service ID %d: %s", *dsV31.ID, err.Error()) } - res, alerts, status, userErr, sysErr := updateV31(w, r, inf, &dsV31) + res, status, userErr, sysErr := updateV31(w, r, inf, &dsV31) if res != nil { - return &res.DeliveryServiceV30, alerts, status, userErr, sysErr + return &res.DeliveryServiceV30, status, userErr, sysErr } - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } -func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 *tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, tc.Alerts, int, error, error) { - var alerts tc.Alerts - +func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 *tc.DeliveryServiceV31) (*tc.DeliveryServiceV31, int, error, error) { dsNull := tc.DeliveryServiceNullableV30(*dsV31) ds := dsNull.UpgradeToV4() dsV40 := ds if dsV40.ID == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("cannot update a Delivery Service with nil ID") + return nil, http.StatusInternalServerError, nil, errors.New("cannot update a Delivery Service with nil ID") } tx := inf.Tx.Tx var sysErr error if dsV40.TLSVersions, sysErr = GetDSTLSVersions(*dsV40.ID, tx); sysErr != nil { - return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("getting TLS versions for DS #%d in API version < 4.0: %w", *dsV40.ID, sysErr) + return nil, http.StatusInternalServerError, nil, fmt.Errorf("getting TLS versions for DS #%d in API version < 4.0: %w", *dsV40.ID, sysErr) } - res, alerts, status, usrErr, sysErr := updateV40(w, r, inf, &dsV40, false) + res, status, usrErr, sysErr := updateV40(w, r, inf, &dsV40, false) if res == nil || usrErr != nil || sysErr != nil { - return nil, alerts, status, usrErr, sysErr + return nil, status, usrErr, sysErr } ds = *res if dsV31.CacheURL != nil { @@ -1092,45 +1056,44 @@ func updateV31(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV31 * &ds.ID) if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, alerts, code, usrErr, sysErr + return nil, code, usrErr, sysErr } } if err := EnsureCacheURLParams(tx, *ds.ID, *ds.XMLID, dsV31.CacheURL); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, err + return nil, http.StatusInternalServerError, nil, err } oldRes := tc.DeliveryServiceV31(ds.DowngradeToV3()) - return &oldRes, alerts, http.StatusOK, nil, nil + return &oldRes, http.StatusOK, nil, nil } -func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 *tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, tc.Alerts, int, error, error) { +func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 *tc.DeliveryServiceV40, omitExtraLongDescFields bool) (*tc.DeliveryServiceV40, int, error, error) { tx := inf.Tx.Tx user := inf.User - var alerts tc.Alerts ds := tc.DeliveryServiceV4(*dsV40) if err := Validate(tx, &ds); err != nil { - return nil, alerts, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil + return nil, http.StatusBadRequest, errors.New("invalid request: " + err.Error()), nil } if authorized, err := isTenantAuthorized(inf, &ds); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("checking tenant: " + err.Error()) } else if !authorized { - return nil, alerts, http.StatusForbidden, errors.New("not authorized on this tenant"), nil + return nil, http.StatusForbidden, errors.New("not authorized on this tenant"), nil } if ds.XMLID == nil { - return nil, alerts, http.StatusBadRequest, errors.New("missing xml_id"), nil + return nil, http.StatusBadRequest, errors.New("missing xml_id"), nil } if ds.ID == nil { - return nil, alerts, http.StatusBadRequest, errors.New("missing id"), nil + return nil, http.StatusBadRequest, errors.New("missing id"), nil } dsType, ok, err := getDSType(tx, *ds.XMLID) if !ok { - return nil, alerts, http.StatusNotFound, errors.New("delivery service '" + *ds.XMLID + "' not found"), nil + return nil, http.StatusNotFound, errors.New("delivery service '" + *ds.XMLID + "' not found"), nil } if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type during update: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type during update: " + err.Error()) } errCode := http.StatusOK @@ -1141,13 +1104,13 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if dsType.HasSSLKeys() { oldDetails, userErr, sysErr, errCode = getOldDetails(*ds.ID, tx) if userErr != nil || sysErr != nil { - return nil, alerts, errCode, userErr, sysErr + return nil, errCode, userErr, sysErr } if sslKeysExist, err = getSSLVersion(*ds.XMLID, tx); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %w", err) + return nil, http.StatusInternalServerError, nil, fmt.Errorf("querying delivery service with sslKeyVersion failed: %w", err) } if ds.CDNID == nil { - return nil, alerts, http.StatusBadRequest, errors.New("invalid request: 'cdnId' cannot be blank"), nil + return nil, http.StatusBadRequest, errors.New("invalid request: 'cdnId' cannot be blank"), nil } if sslKeysExist { if oldDetails.OldCdnId != *ds.CDNID { @@ -1160,7 +1123,7 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * cdnRoutingDetailDiff = true } if cdnRoutingDetailDiff { - return nil, alerts, http.StatusBadRequest, errors.New("delivery service has ssl keys that cannot be automatically changed, therefore CDN and routing name are immutable"), nil + return nil, http.StatusBadRequest, errors.New("delivery service has ssl keys that cannot be automatically changed, therefore CDN and routing name are immutable"), nil } ds.SSLKeyVersion = oldDetails.OldSSLKeyVersion } @@ -1174,34 +1137,34 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * userErr, sysErr, errCode = api.CheckIfUnModified(r.Header, inf.Tx, *ds.ID, "deliveryservice") if userErr != nil || sysErr != nil { - return nil, alerts, errCode, userErr, sysErr + return nil, errCode, userErr, sysErr } if errCode, userErr, sysErr = dbhelpers.CheckTopology(inf.Tx, ds); userErr != nil || sysErr != nil { - return nil, alerts, errCode, userErr, sysErr + return nil, errCode, userErr, sysErr } if ds.Topology != nil { requiredCapabilities, err := dbhelpers.GetDSRequiredCapabilitiesFromID(*ds.ID, tx) if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting existing DS required capabilities: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("getting existing DS required capabilities: " + err.Error()) } if len(requiredCapabilities) > 0 { if userErr, sysErr, status := EnsureTopologyBasedRequiredCapabilities(tx, *ds.ID, *ds.Topology, requiredCapabilities); userErr != nil || sysErr != nil { - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } } userErr, sysErr, status := dbhelpers.CheckOriginServerInDSCG(tx, *ds.ID, *ds.Topology) if userErr != nil || sysErr != nil { - return nil, alerts, status, userErr, sysErr + return nil, status, userErr, sysErr } } var resultRows *sql.Rows if omitExtraLongDescFields { if ds.LongDesc1 != nil || ds.LongDesc2 != nil { - return nil, alerts, http.StatusBadRequest, errors.New("the longDesc1 and longDesc2 fields are no longer supported in API 4.0 onwards"), 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, @@ -1328,35 +1291,35 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * if err != nil { usrErr, sysErr, code := api.ParseDBError(err) - return nil, alerts, code, usrErr, sysErr + return nil, code, usrErr, sysErr } defer resultRows.Close() if !resultRows.Next() { - return nil, alerts, http.StatusNotFound, errors.New("no delivery service found with this id"), nil + 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, alerts, http.StatusInternalServerError, nil, errors.New("scan updating delivery service: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("scan updating delivery service: " + err.Error()) } if resultRows.Next() { xmlID := "" if ds.XMLID != nil { xmlID = *ds.XMLID } - return nil, alerts, http.StatusInternalServerError, nil, errors.New("updating delivery service " + xmlID + ": " + "this update affected too many rows: > 1") + return nil, http.StatusInternalServerError, nil, errors.New("updating delivery service " + xmlID + ": " + "this update affected too many rows: > 1") } if ds.ID == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing id after update") + return nil, http.StatusInternalServerError, nil, errors.New("missing id after update") } if ds.XMLID == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing XMLID after update") + return nil, http.StatusInternalServerError, nil, errors.New("missing XMLID after update") } if ds.TypeID == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing type id after update") + return nil, http.StatusInternalServerError, nil, errors.New("missing type id after update") } if ds.RoutingName == nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("missing routing name after update") + return nil, http.StatusInternalServerError, nil, errors.New("missing routing name after update") } if len(ds.TLSVersions) < 1 { @@ -1364,37 +1327,37 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * } err = recreateTLSVersions(ds.TLSVersions, *ds.ID, tx) if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, fmt.Errorf("updating TLS versions for DS #%d: %w", *ds.ID, err) + 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, alerts, http.StatusInternalServerError, nil, errors.New("getting delivery service type after update: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("getting delivery service type after update: " + err.Error()) } ds.Type = &newDSType cdnDomain, err := getCDNDomain(*ds.ID, tx) // need to get the domain again, in case it changed. if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting CDN domain: (" + cdnDomain + ") after update: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("getting CDN domain: (" + cdnDomain + ") after update: " + err.Error()) } matchLists, err := GetDeliveryServicesMatchLists([]string{*ds.XMLID}, tx) if err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("getting matchlists after update: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("getting matchlists after update: " + err.Error()) } if ml, ok := matchLists[*ds.XMLID]; !ok { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("no matchlists after update") + return nil, http.StatusInternalServerError, nil, errors.New("no matchlists after update") } else { 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, alerts, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " + err.Error()) } if oldDetails.OldOrgServerFqdn != nil && ds.OrgServerFQDN != nil && *oldDetails.OldOrgServerFqdn != *ds.OrgServerFQDN { if err := updatePrimaryOrigin(tx, user, ds); err != nil { - return nil, alerts, http.StatusInternalServerError, nil, errors.New("updating delivery service: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("updating delivery service: " + err.Error()) } } @@ -1403,24 +1366,22 @@ func updateV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 * // 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, alerts, http.StatusInternalServerError, nil, fmt.Errorf("deleting consistent hash query params for ds %s: %w", *ds.XMLID, err) + 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, alerts, code, usrErr, sysErr + 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, alerts, http.StatusInternalServerError, nil, errors.New("writing change log entry: " + err.Error()) + return nil, http.StatusInternalServerError, nil, errors.New("writing change log entry: " + err.Error()) } - alerts = generateTLSVersionWarnings(ds, tx) - dsV40 = (*tc.DeliveryServiceV40)(&ds) - return dsV40, alerts, http.StatusOK, nil, nil + return dsV40, http.StatusOK, nil, nil } //Delete is the DeliveryService implementation of the Deleter interface. From e0674ea5e24ab42324730411e042c06c01544239 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 15 Jun 2021 14:56:07 -0600 Subject: [PATCH 29/34] re-use query for TLS Versions --- .../deliveryservice/deliveryservices.go | 34 ++++--------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 0febddb39d..7a16135fdf 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -110,38 +110,20 @@ func (ds *TODeliveryService) IsTenantAuthorized(user *auth.CurrentUser) (bool, e return isTenantAuthorized(ds.ReqInfo, &ds.DeliveryServiceV4) } -const getTLSVersionsQuery = ` -SELECT tls_version -FROM public.deliveryservice_tls_version +const baseTLSVersionsQuery = `SELECT ARRAY_AGG(tls_version ORDER BY tls_version) FROM deliveryservice_tls_version` + +const getTLSVersionsQuery = baseTLSVersionsQuery + ` WHERE deliveryservice = $1 -ORDER BY tls_version ` // GetDSTLSVersions retrieves the TLS versions explicitly supported by a // Delivery Service identified by dsID. This will panic if handed a nil // transaction. func GetDSTLSVersions(dsID int, tx *sql.Tx) ([]string, error) { - rows, err := tx.Query(getTLSVersionsQuery, dsID) - if err != nil { - return nil, fmt.Errorf("querying: %w", err) - } - defer func() { - if err := rows.Close(); err != nil { - log.Errorf("closing TLS versions rows: %v", err) - } - }() - var vers []string - for rows.Next() { - var ver string - if err = rows.Scan(&ver); err != nil { - return nil, fmt.Errorf("scanning: %w", err) - } - vers = append(vers, ver) - } - err = rows.Err() + err := tx.QueryRow(getTLSVersionsQuery, dsID).Scan(pq.Array(&vers)) if err != nil { - err = fmt.Errorf("iteration error: %w", err) + err = fmt.Errorf("querying: %w", err) } return vers, err } @@ -2466,11 +2448,7 @@ ds.active, ds.ssl_key_version, ds.tenant_id, tenant.name, - ( - SELECT ARRAY_AGG(tls_version ORDER BY tls_version) - FROM deliveryservice_tls_version - WHERE deliveryservice = ds.id - ) AS tls_versions, + (` + baseTLSVersionsQuery + ` WHERE deliveryservice = ds.id) AS tls_versions, ds.topology, ds.tr_request_headers, ds.tr_response_headers, From d6970f8e458207e007dd1ee36ffa0d50f1e7a5a9 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 16 Jun 2021 11:22:54 -0600 Subject: [PATCH 30/34] Fix tests for new query structure --- .../deliveryservice/deliveryservices_test.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go index 9f32afb4e4..41a9ed5004 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go @@ -20,8 +20,10 @@ package deliveryservice */ import ( + "fmt" "net/http" "reflect" + "strings" "testing" "time" @@ -146,13 +148,10 @@ func TestGetDSTLSVersions(t *testing.T) { rows := sqlmock.NewRows([]string{"tls_version"}) expected := []string{"1.0", "1.1", "1.2", "1.3"} - rows.AddRow(expected[0]) - rows.AddRow(expected[1]) - rows.AddRow(expected[2]) - rows.AddRow(expected[3]) + rows.AddRow(fmt.Sprintf("{%s}", strings.Join(expected, ","))) mock.ExpectBegin() - mock.ExpectQuery("SELECT tls_version").WillReturnRows(rows) + mock.ExpectQuery("SELECT").WillReturnRows(rows) vers, err := GetDSTLSVersions(0, db.MustBegin().Tx) if err != nil { @@ -160,7 +159,7 @@ func TestGetDSTLSVersions(t *testing.T) { } else if len(vers) != 4 { t.Errorf("Expected to get 4 TLS versions, got: %d", len(vers)) } else if !reflect.DeepEqual(expected, vers) { - t.Errorf("Incorrect TLS versions returned, expected: %v - actual: %v", expected, vers) + t.Errorf("Incorrect TLS versions returned, expected: %+v - actual: %+v", expected, vers) } } From ecac684b7c5066774c8fd353e8a15d15ed609d75 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 16 Jun 2021 14:35:57 -0600 Subject: [PATCH 31/34] Revert all breaking DS changes --- lib/go-tc/deliveryservices.go | 816 +++++++----------- lib/go-tc/deliveryservices_test.go | 147 ++-- .../testing/api/v4/deliveryservices_test.go | 37 +- .../deliveryservice/deliveryservices.go | 18 +- 4 files changed, 408 insertions(+), 610 deletions(-) diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go index f178b96aff..de34134478 100644 --- a/lib/go-tc/deliveryservices.go +++ b/lib/go-tc/deliveryservices.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "strings" - "time" "github.com/apache/trafficcontrol/lib/go-util" ) @@ -188,12 +187,290 @@ type DeliveryServiceV31 struct { // DeliveryServiceFieldsV31 contains additions to delivery services in api v3.1 type DeliveryServiceFieldsV31 struct { + // MaxRequestHeaderBytes is the maximum size (in bytes) of the request + // header that is allowed for this Delivery Service. MaxRequestHeaderBytes *int `json:"maxRequestHeaderBytes" db:"max_request_header_bytes"` } // DeliveryServiceV40 is a Delivery Service as it appears in version 4.0 of the // Traffic Ops API. type DeliveryServiceV40 struct { + DeliveryServiceFieldsV31 + DeliveryServiceFieldsV30 + DeliveryServiceFieldsV15 + DeliveryServiceFieldsV14 + DeliveryServiceFieldsV13 + DeliveryServiceNullableFieldsV11 + + // TLSVersions is the list of explicitly supported TLS versions for cache + // servers serving the Delivery Service's content. + TLSVersions []string `json:"tlsVersions" db:"tls_versions"` +} + +// DeliveryServiceV4 is a Delivery Service as it appears in version 4 of the +// Traffic Ops API - it always points to the highest minor version in APIv4. +type DeliveryServiceV4 = DeliveryServiceV40 + +// These are the TLS Versions known by Apache Traffic Control to exist. +const ( + // Deprecated: TLS version 1.0 is known to be insecure. + TLSVersion10 = "1.0" + // Deprecated: TLS version 1.1 is known to be insecure. + TLSVersion11 = "1.1" + TLSVersion12 = "1.2" + TLSVersion13 = "1.3" +) + +func newerTLSVersionsDisallowedMessage(old string, newer []string) string { + l := len(newer) + if l < 1 { + return "" + } + + var msg strings.Builder + msg.WriteString("old TLS version ") + msg.WriteString(old) + msg.WriteString(" is allowed, but newer version") + if l > 1 { + msg.WriteRune('s') + } + msg.WriteRune(' ') + msg.WriteString(newer[0]) + if l > 1 { + msg.WriteString(", ") + if l > 2 { + msg.WriteString(newer[1]) + msg.WriteString(", and ") + msg.WriteString(newer[2]) + } else { + msg.WriteString("and ") + msg.WriteString(newer[1]) + } + msg.WriteString(" are ") + } else { + msg.WriteString(" is ") + } + msg.WriteString("disallowed; this configuration may be insecure") + + return msg.String() +} + +// TLSVersionsAlerts generates warning-level alerts for the Delivery Service's +// TLS versions array. It will warn if newer versions are disallowed while +// older, less secure versions are allowed, if there are unrecognized versions +// present, if the Delivery Service's Protocol does not make use of TLS +// Versions, and whenever TLSVersions are explicitly set at all. +// +// This does NOT verify that the Delivery Service's TLS versions are _valid_, +// it ONLY creates warnings based on conditions that are possibly detrimental +// to CDN operation, but can, in fact, work. +func (ds DeliveryServiceV4) TLSVersionsAlerts() Alerts { + vers := ds.TLSVersions + messages := []string{} + + if len(vers) > 0 { + messages = append(messages, "setting TLS Versions that are explicitly supported may break older clients that can't use the specified versions") + } else { + return Alerts{Alerts: []Alert{}} + } + + found := map[string]bool{ + TLSVersion10: false, + TLSVersion11: false, + TLSVersion12: false, + TLSVersion13: false, + } + + for _, v := range vers { + switch v { + case TLSVersion10: + found[TLSVersion10] = true + case TLSVersion11: + found[TLSVersion11] = true + case TLSVersion12: + found[TLSVersion12] = true + case TLSVersion13: + found[TLSVersion13] = true + default: + messages = append(messages, "unknown TLS version '"+v+"' - possible typo") + } + } + + if found[TLSVersion10] { + var newerDisallowed []string + if !found[TLSVersion11] { + newerDisallowed = append(newerDisallowed, TLSVersion11) + } + if !found[TLSVersion12] { + newerDisallowed = append(newerDisallowed, TLSVersion12) + } + if !found[TLSVersion13] { + newerDisallowed = append(newerDisallowed, TLSVersion13) + } + msg := newerTLSVersionsDisallowedMessage(TLSVersion10, newerDisallowed) + if msg != "" { + messages = append(messages, msg) + } + } else if found[TLSVersion11] { + var newerDisallowed []string + if !found[TLSVersion12] { + newerDisallowed = append(newerDisallowed, TLSVersion12) + } + if !found[TLSVersion13] { + newerDisallowed = append(newerDisallowed, TLSVersion13) + } + msg := newerTLSVersionsDisallowedMessage(TLSVersion11, newerDisallowed) + if msg != "" { + messages = append(messages, msg) + } + } else if found[TLSVersion12] { + var newerDisallowed []string + if !found[TLSVersion13] { + newerDisallowed = append(newerDisallowed, TLSVersion13) + } + msg := newerTLSVersionsDisallowedMessage(TLSVersion12, newerDisallowed) + if msg != "" { + messages = append(messages, msg) + } + } + + if ds.Protocol != nil && *ds.Protocol == DSProtocolHTTP { + messages = append(messages, "tlsVersions has no effect on Delivery Services with Protocol '0' (HTTP_ONLY)") + } + + return CreateAlerts(WarnLevel, messages...) +} + +type DeliveryServiceV30 struct { + DeliveryServiceNullableV15 + DeliveryServiceFieldsV30 +} + +// DeliveryServiceFieldsV30 contains additions to delivery services in api v3.0. +type DeliveryServiceFieldsV30 struct { + // FirstHeaderRewrite is a "header rewrite rule" used by ATS at the first + // caching layer encountered in the Delivery Service's Topology, or nil if + // there is no such rule. This has no effect on Delivery Services that don't + // employ Topologies. + FirstHeaderRewrite *string `json:"firstHeaderRewrite" db:"first_header_rewrite"` + // InnerHeaderRewrite is a "header rewrite rule" used by ATS at all caching + // layers encountered in the Delivery Service's Topology except the first + // and last, or nil if there is no such rule. This has no effect on Delivery + // Services that don't employ Topologies. + InnerHeaderRewrite *string `json:"innerHeaderRewrite" db:"inner_header_rewrite"` + // LastHeaderRewrite is a "header rewrite rule" used by ATS at the first + // caching layer encountered in the Delivery Service's Topology, or nil if + // there is no such rule. This has no effect on Delivery Services that don't + // employ Topologies. + LastHeaderRewrite *string `json:"lastHeaderRewrite" db:"last_header_rewrite"` + // ServiceCategory defines a category to which a Delivery Service may + // belong, which will cause HTTP Responses containing content for the + // Delivery Service to have the "X-CDN-SVC" header with a value that is the + // XMLID of the Delivery Service. + ServiceCategory *string `json:"serviceCategory" db:"service_category"` + // Topology is the name of the Topology used by the Delivery Service, or nil + // if no Topology is used. + Topology *string `json:"topology" db:"topology"` +} + +// DeliveryServiceNullableV30 is the aliased structure that we should be using for all api 3.x delivery structure operations +// This type should always alias the latest 3.x minor version struct. For ex, if you wanted to create a DeliveryServiceV32 struct, you would do the following: +// type DeliveryServiceNullableV30 DeliveryServiceV32 +// DeliveryServiceV32 = DeliveryServiceV31 + the new fields. +type DeliveryServiceNullableV30 DeliveryServiceV31 + +// Deprecated: Use versioned structures only from now on. +type DeliveryServiceNullable DeliveryServiceNullableV15 +type DeliveryServiceNullableV15 struct { + DeliveryServiceNullableV14 + DeliveryServiceFieldsV15 +} + +// DeliveryServiceFieldsV15 contains additions to delivery services in api v1.5. +type DeliveryServiceFieldsV15 struct { + // EcsEnabled describes whether or not the Traffic Router's EDNS0 Client + // Subnet extensions should be enabled when serving DNS responses for this + // Delivery Service. Even if this is true, the Traffic Router may still + // have the extensions unilaterally disabled in its own configuration. + EcsEnabled bool `json:"ecsEnabled" db:"ecs_enabled"` + // RangeSliceBlockSize defines the size of range request blocks - or + // "slices" - used by the "slice" plugin. This has no effect if + // RangeRequestHandling does not point to exactly 3. This may never legally + // point to a value less than zero. + RangeSliceBlockSize *int `json:"rangeSliceBlockSize" db:"range_slice_block_size"` +} + +type DeliveryServiceNullableV14 struct { + DeliveryServiceNullableV13 + DeliveryServiceFieldsV14 +} + +// DeliveryServiceFieldsV14 contains additions to delivery services in api v1.4. +type DeliveryServiceFieldsV14 struct { + // ConsistentHashRegex is used by Traffic Router to extract meaningful parts + // of a client's request URI for HTTP-routed Delivery Services before + // hashing the request to find a cache server to which to direct the client. + ConsistentHashRegex *string `json:"consistentHashRegex"` + // ConsistentHashQueryParams is a list of al of the query string parameters + // which ought to be considered by Traffic Router in client request URIs for + // HTTP-routed Delivery Services in the hashing process. + ConsistentHashQueryParams []string `json:"consistentHashQueryParams"` + // MaxOriginConnections defines the total maximum number of connections + // that the highest caching layer ("Mid-tier" in a non-Topology context) is + // allowed to have concurrently open to the Delivery Service's Origin. This + // may never legally point to a value less than 0. + MaxOriginConnections *int `json:"maxOriginConnections" db:"max_origin_connections"` +} + +type DeliveryServiceNullableV13 struct { + DeliveryServiceNullableV12 + DeliveryServiceFieldsV13 +} + +// DeliveryServiceFieldsV13 contains additions to delivery services in api v1.3. +type DeliveryServiceFieldsV13 struct { + // DeepCachingType may only legally point to 'ALWAYS' or 'NEVER', which + // define whether "deep caching" may or may not be used for this Delivery + // Service, respectively. + DeepCachingType *DeepCachingType `json:"deepCachingType" db:"deep_caching_type"` + // FQPacingRate sets the maximum bytes per second a cache server will deliver + // on any single TCP connection for this Delivery Service. This may never + // legally point to a value less than zero. + FQPacingRate *int `json:"fqPacingRate" db:"fq_pacing_rate"` + // SigningAlgorithm is the name of the algorithm used to sign CDN URIs for + // this Delivery Service's content, or nil if no URI signing is done for the + // Delivery Service. This may only point to the values "url_sig" or + // "uri_signing". + SigningAlgorithm *string `json:"signingAlgorithm" db:"signing_algorithm"` + // Tenant is the Tenant to which the Delivery Service belongs. + Tenant *string `json:"tenant"` + // TRResponseHeaders is a set of headers (separated by CRLF pairs as per the + // HTTP spec) and their values (separated by a colon as per the HTTP spec) + // which will be sent by Traffic Router in HTTP responses to client requests + // for this Delivery Service's content. This has no effect on DNS-routed or + // un-routed Delivery Service Types. + TRResponseHeaders *string `json:"trResponseHeaders"` + // TRRequestHeaders is an "array" of HTTP headers which should be logged + // from client HTTP requests for this Delivery Service's content by Traffic + // Router, separated by newlines. This has no effect on DNS-routed or + // un-routed Delivery Service Types. + TRRequestHeaders *string `json:"trRequestHeaders"` +} + +type DeliveryServiceNullableV12 struct { + DeliveryServiceNullableV11 +} + +// DeliveryServiceNullableV11 is a version of the deliveryservice that allows +// for all fields to be null. +// +// TODO: move contents to DeliveryServiceNullableV12, fix references, and remove this. +type DeliveryServiceNullableV11 struct { + DeliveryServiceNullableFieldsV11 + DeliveryServiceRemovedFieldsV11 +} + +type DeliveryServiceNullableFieldsV11 struct { // Active dictates whether the Delivery Service is routed by Traffic Router. Active *bool `json:"active" db:"active"` // AnonymousBlockingEnabled sets whether or not anonymized IP addresses @@ -211,18 +488,6 @@ type DeliveryServiceV40 struct { // CheckPath is a path which may be requested of the Delivery Service's // origin to ensure it's working properly. CheckPath *string `json:"checkPath" db:"check_path"` - // ConsistentHashQueryParams is a list of al of the query string parameters - // which ought to be considered by Traffic Router in client request URIs for - // HTTP-routed Delivery Services in the hashing process. - ConsistentHashQueryParams []string `json:"consistentHashQueryParams"` - // ConsistentHashRegex is used by Traffic Router to extract meaningful parts - // of a client's request URI for HTTP-routed Delivery Services before - // hashing the request to find a cache server to which to direct the client. - ConsistentHashRegex *string `json:"consistentHashRegex"` - // DeepCachingType may only legally point to 'ALWAYS' or 'NEVER', which - // define whether "deep caching" may or may not be used for this Delivery - // Service, respectively. - DeepCachingType *DeepCachingType `json:"deepCachingType" db:"deep_caching_type"` // DisplayName is a human-friendly name that might be used in some UIs // somewhere. DisplayName *string `json:"displayName" db:"display_name"` @@ -242,12 +507,7 @@ type DeliveryServiceV40 struct { // transferred between clients, origins, and cache servers when obtaining // and serving content for this Delivery Service. // See Also: https://en.wikipedia.org/wiki/Differentiated_services - DSCP *int `json:"dscp" db:"dscp"` - // EcsEnabled describes whether or not the Traffic Router's EDNS0 Client - // Subnet extensions should be enabled when serving DNS responses for this - // Delivery Service. Even if this is true, the Traffic Router may still - // have the extensions unilaterally disabled in its own configuration. - EcsEnabled bool `json:"ecsEnabled" db:"ecs_enabled"` + DSCP *int `json:"dscp" db:"dscp"` // EdgeHeaderRewrite is a "header rewrite rule" used by ATS at the Edge-tier // of caching. This has no effect on Delivery Services that don't use a // Topology. @@ -255,15 +515,6 @@ type DeliveryServiceV40 struct { // ExampleURLs is a list of all of the URLs from which content may be // requested from the Delivery Service. ExampleURLs []string `json:"exampleURLs"` - // FirstHeaderRewrite is a "header rewrite rule" used by ATS at the first - // caching layer encountered in the Delivery Service's Topology, or nil if - // there is no such rule. This has no effect on Delivery Services that don't - // employ Topologies. - FirstHeaderRewrite *string `json:"firstHeaderRewrite" db:"first_header_rewrite"` - // FQPacingRate sets the maximum bytes per second a cache server will deliver - // on any single TCP connection for this Delivery Service. This may never - // legally point to a value less than zero. - FQPacingRate *int `json:"fqPacingRate" db:"fq_pacing_rate"` // GeoLimit defines whether or not access to a Delivery Service's content // should be limited based on the requesting client's geographic location. // Despite that this is a pointer to an arbitrary integer, the only valid @@ -309,22 +560,12 @@ type DeliveryServiceV40 struct { // caching layer ("Edge-tier" in a non-Topology context) across which // content will be dispersed per Cache Group. InitialDispersion *int `json:"initialDispersion" db:"initial_dispersion"` - // InnerHeaderRewrite is a "header rewrite rule" used by ATS at all caching - // layers encountered in the Delivery Service's Topology except the first - // and last, or nil if there is no such rule. This has no effect on Delivery - // Services that don't employ Topologies. - InnerHeaderRewrite *string `json:"innerHeaderRewrite" db:"inner_header_rewrite"` // IPV6RoutingEnabled controls whether or not routing over IPv6 should be // done for this Delivery Service. IPV6RoutingEnabled *bool `json:"ipv6RoutingEnabled" db:"ipv6_routing_enabled"` - // LastHeaderRewrite is a "header rewrite rule" used by ATS at the first - // caching layer encountered in the Delivery Service's Topology, or nil if - // there is no such rule. This has no effect on Delivery Services that don't - // employ Topologies. - LastHeaderRewrite *string `json:"lastHeaderRewrite" db:"last_header_rewrite"` // LastUpdated is the time and date at which the Delivery Service was last // updated. - LastUpdated time.Time `json:"lastUpdated" db:"last_updated"` + LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"` // LogsEnabled controls nothing. It is kept only for legacy compatibility. LogsEnabled *bool `json:"logsEnabled" db:"logs_enabled"` // LongDesc is a description of the Delivery Service, having arbitrary @@ -338,19 +579,11 @@ type DeliveryServiceV40 struct { LongDesc2 *string `json:"longDesc2" db:"long_desc_2"` // MatchList is a list of Regular Expressions used for routing the Delivery // Service. Order matters, and the array is not allowed to be sparse. - MatchList []DeliveryServiceMatch `json:"matchList"` + MatchList *[]DeliveryServiceMatch `json:"matchList"` // MaxDNSAnswers sets the maximum number of records which should be returned // by Traffic Router in DNS responses to requests for resolving names for // this Delivery Service. MaxDNSAnswers *int `json:"maxDnsAnswers" db:"max_dns_answers"` - // MaxOriginConnections defines the total maximum number of connections - // that the highest caching layer ("Mid-tier" in a non-Topology context) is - // allowed to have concurrently open to the Delivery Service's Origin. This - // may never legally point to a value less than 0. - MaxOriginConnections *int `json:"maxOriginConnections" db:"max_origin_connections"` - // MaxRequestHeaderBytes is the maximum size (in bytes) of the request - // header that is allowed for this Delivery Service. - MaxRequestHeaderBytes *int `json:"maxRequestHeaderBytes" db:"max_request_header_bytes"` // MidHeaderRewrite is a "header rewrite rule" used by ATS at the Mid-tier // of caching. This has no effect on Delivery Services that don't use a // Topology. @@ -406,11 +639,6 @@ type DeliveryServiceV40 struct { // implies that the slice plugin will be used to slice range based requests // into deterministic chunks.) RangeRequestHandling *int `json:"rangeRequestHandling" db:"range_request_handling"` - // RangeSliceBlockSize defines the size of range request blocks - or - // "slices" - used by the "slice" plugin. This has no effect if - // RangeRequestHandling does not point to exactly 3. This may never legally - // point to a value less than zero. - RangeSliceBlockSize *int `json:"rangeSliceBlockSize" db:"range_slice_block_size"` // Regex Remap is a raw line to be inserted into "regex_remap.config" on the // cache server. Care is necessitated in its use, because the input is in no // way restricted, validated, or limited in scope to the Delivery Service. @@ -429,44 +657,15 @@ type DeliveryServiceV40 struct { // Service, e.g. if trafficcontrol.apache.org were a Delivery Service, it // would have a RoutingName of "trafficcontrol". RoutingName *string `json:"routingName" db:"routing_name"` - // ServiceCategory defines a category to which a Delivery Service may - // belong, which will cause HTTP Responses containing content for the - // Delivery Service to have the "X-CDN-SVC" header with a value that is the - // XMLID of the Delivery Service. - ServiceCategory *string `json:"serviceCategory" db:"service_category"` // Signed is a legacy field. It is allowed to be `true` if and only if // SigningAlgorithm is not nil. Signed bool `json:"signed"` - // SigningAlgorithm is the name of the algorithm used to sign CDN URIs for - // this Delivery Service's content, or nil if no URI signing is done for the - // Delivery Service. This may only point to the values "url_sig" or - // "uri_signing". - SigningAlgorithm *string `json:"signingAlgorithm" db:"signing_algorithm"` // SSLKeyVersion incremented whenever Traffic Portal generates new SSL keys // for the Delivery Service, effectively making it a "generational" marker. SSLKeyVersion *int `json:"sslKeyVersion" db:"ssl_key_version"` - // Tenant is the Tenant to which the Delivery Service belongs. - Tenant *string `json:"tenant"` // TenantID is the integral, unique identifier for the Tenant to which the // Delivery Service belongs. TenantID *int `json:"tenantId" db:"tenant_id"` - // TLSVersions is the list of explicitly supported TLS versions for cache - // servers serving the Delivery Service's content. - TLSVersions []string `json:"tlsVersions" db:"tls_versions"` - // Topology is the name of the Topology used by the Delivery Service, or nil - // if no Topology is used. - Topology *string `json:"topology" db:"topology"` - // TRResponseHeaders is a set of headers (separated by CRLF pairs as per the - // HTTP spec) and their values (separated by a colon as per the HTTP spec) - // which will be sent by Traffic Router in HTTP responses to client requests - // for this Delivery Service's content. This has no effect on DNS-routed or - // un-routed Delivery Service Types. - TRResponseHeaders *string `json:"trResponseHeaders"` - // TRRequestHeaders is an "array" of HTTP headers which should be logged - // from client HTTP requests for this Delivery Service's content by Traffic - // Router, separated by newlines. This has no effect on DNS-routed or - // un-routed Delivery Service Types. - TRRequestHeaders *string `json:"trRequestHeaders"` // Type describes how content is routed and cached for this Delivery Service // as well as what other properties have any meaning. Type *DSType `json:"type"` @@ -480,269 +679,6 @@ type DeliveryServiceV40 struct { XMLID *string `json:"xmlId" db:"xml_id"` } -// DeliveryServiceV4 is a Delivery Service as it appears in version 4 of the -// Traffic Ops API - it always points to the highest minor version in APIv4. -type DeliveryServiceV4 = DeliveryServiceV40 - -// These are the TLS Versions known by Apache Traffic Control to exist. -const ( - // Deprecated: TLS version 1.0 is known to be insecure. - TLSVersion10 = "1.0" - // Deprecated: TLS version 1.1 is known to be insecure. - TLSVersion11 = "1.1" - TLSVersion12 = "1.2" - TLSVersion13 = "1.3" -) - -func newerTLSVersionsDisallowedMessage(old string, newer []string) string { - l := len(newer) - if l < 1 { - return "" - } - - var msg strings.Builder - msg.WriteString("old TLS version ") - msg.WriteString(old) - msg.WriteString(" is allowed, but newer version") - if l > 1 { - msg.WriteRune('s') - } - msg.WriteRune(' ') - msg.WriteString(newer[0]) - if l > 1 { - msg.WriteString(", ") - if l > 2 { - msg.WriteString(newer[1]) - msg.WriteString(", and ") - msg.WriteString(newer[2]) - } else { - msg.WriteString("and ") - msg.WriteString(newer[1]) - } - msg.WriteString(" are ") - } else { - msg.WriteString(" is ") - } - msg.WriteString("disallowed; this configuration may be insecure") - - return msg.String() -} - -// TLSVersionsAlerts generates warning-level alerts for the Delivery Service's -// TLS versions array. It will warn if newer versions are disallowed while -// older, less secure versions are allowed, if there are unrecognized versions -// present, if the Delivery Service's Protocol does not make use of TLS -// Versions, and whenever TLSVersions are explicitly set at all. -// -// This does NOT verify that the Delivery Service's TLS versions are _valid_, -// it ONLY creates warnings based on conditions that are possibly detrimental -// to CDN operation, but can, in fact, work. -func (ds DeliveryServiceV4) TLSVersionsAlerts() Alerts { - vers := ds.TLSVersions - messages := []string{} - - if len(vers) > 0 { - messages = append(messages, "setting TLS Versions that are explicitly supported may break older clients that can't use the specified versions") - } else { - return Alerts{Alerts: []Alert{}} - } - - found := map[string]bool{ - TLSVersion10: false, - TLSVersion11: false, - TLSVersion12: false, - TLSVersion13: false, - } - - for _, v := range vers { - switch v { - case TLSVersion10: - found[TLSVersion10] = true - case TLSVersion11: - found[TLSVersion11] = true - case TLSVersion12: - found[TLSVersion12] = true - case TLSVersion13: - found[TLSVersion13] = true - default: - messages = append(messages, "unknown TLS version '"+v+"' - possible typo") - } - } - - if found[TLSVersion10] { - var newerDisallowed []string - if !found[TLSVersion11] { - newerDisallowed = append(newerDisallowed, TLSVersion11) - } - if !found[TLSVersion12] { - newerDisallowed = append(newerDisallowed, TLSVersion12) - } - if !found[TLSVersion13] { - newerDisallowed = append(newerDisallowed, TLSVersion13) - } - msg := newerTLSVersionsDisallowedMessage(TLSVersion10, newerDisallowed) - if msg != "" { - messages = append(messages, msg) - } - } else if found[TLSVersion11] { - var newerDisallowed []string - if !found[TLSVersion12] { - newerDisallowed = append(newerDisallowed, TLSVersion12) - } - if !found[TLSVersion13] { - newerDisallowed = append(newerDisallowed, TLSVersion13) - } - msg := newerTLSVersionsDisallowedMessage(TLSVersion11, newerDisallowed) - if msg != "" { - messages = append(messages, msg) - } - } else if found[TLSVersion12] { - var newerDisallowed []string - if !found[TLSVersion13] { - newerDisallowed = append(newerDisallowed, TLSVersion13) - } - msg := newerTLSVersionsDisallowedMessage(TLSVersion12, newerDisallowed) - if msg != "" { - messages = append(messages, msg) - } - } - - if ds.Protocol != nil && *ds.Protocol == DSProtocolHTTP { - messages = append(messages, "tlsVersions has no effect on Delivery Services with Protocol '0' (HTTP_ONLY)") - } - - return CreateAlerts(WarnLevel, messages...) -} - -type DeliveryServiceV30 struct { - DeliveryServiceNullableV15 - DeliveryServiceFieldsV30 -} - -// DeliveryServiceFieldsV30 contains additions to delivery services in api v3.0 -type DeliveryServiceFieldsV30 struct { - Topology *string `json:"topology" db:"topology"` - FirstHeaderRewrite *string `json:"firstHeaderRewrite" db:"first_header_rewrite"` - InnerHeaderRewrite *string `json:"innerHeaderRewrite" db:"inner_header_rewrite"` - LastHeaderRewrite *string `json:"lastHeaderRewrite" db:"last_header_rewrite"` - ServiceCategory *string `json:"serviceCategory" db:"service_category"` -} - -// DeliveryServiceNullableV30 is the aliased structure that we should be using for all api 3.x delivery structure operations -// This type should always alias the latest 3.x minor version struct. For ex, if you wanted to create a DeliveryServiceV32 struct, you would do the following: -// type DeliveryServiceNullableV30 DeliveryServiceV32 -// DeliveryServiceV32 = DeliveryServiceV31 + the new fields -type DeliveryServiceNullableV30 DeliveryServiceV31 - -// Deprecated: Use versioned structures only from now on. -type DeliveryServiceNullable DeliveryServiceNullableV15 -type DeliveryServiceNullableV15 struct { - DeliveryServiceNullableV14 - DeliveryServiceFieldsV15 -} - -// DeliveryServiceFieldsV15 contains additions to delivery services in api v1.5 -type DeliveryServiceFieldsV15 struct { - EcsEnabled bool `json:"ecsEnabled" db:"ecs_enabled"` - RangeSliceBlockSize *int `json:"rangeSliceBlockSize" db:"range_slice_block_size"` -} - -type DeliveryServiceNullableV14 struct { - DeliveryServiceNullableV13 - DeliveryServiceFieldsV14 -} - -// DeliveryServiceFieldsV14 contains additions to delivery services in api v1.4 -type DeliveryServiceFieldsV14 struct { - ConsistentHashRegex *string `json:"consistentHashRegex"` - ConsistentHashQueryParams []string `json:"consistentHashQueryParams"` - MaxOriginConnections *int `json:"maxOriginConnections" db:"max_origin_connections"` -} - -type DeliveryServiceNullableV13 struct { - DeliveryServiceNullableV12 - DeliveryServiceFieldsV13 -} - -// DeliveryServiceFieldsV13 contains additions to delivery services in api v1.3 -type DeliveryServiceFieldsV13 struct { - DeepCachingType *DeepCachingType `json:"deepCachingType" db:"deep_caching_type"` - FQPacingRate *int `json:"fqPacingRate" db:"fq_pacing_rate"` - SigningAlgorithm *string `json:"signingAlgorithm" db:"signing_algorithm"` - Tenant *string `json:"tenant"` - TRResponseHeaders *string `json:"trResponseHeaders"` - TRRequestHeaders *string `json:"trRequestHeaders"` -} - -type DeliveryServiceNullableV12 struct { - DeliveryServiceNullableV11 -} - -// DeliveryServiceNullableV11 is a version of the deliveryservice that allows -// for all fields to be null. -// TODO move contents to DeliveryServiceNullableV12, fix references, and remove -type DeliveryServiceNullableV11 struct { - DeliveryServiceNullableFieldsV11 - DeliveryServiceRemovedFieldsV11 -} - -type DeliveryServiceNullableFieldsV11 struct { - Active *bool `json:"active" db:"active"` - AnonymousBlockingEnabled *bool `json:"anonymousBlockingEnabled" db:"anonymous_blocking_enabled"` - CCRDNSTTL *int `json:"ccrDnsTtl" db:"ccr_dns_ttl"` - CDNID *int `json:"cdnId" db:"cdn_id"` - CDNName *string `json:"cdnName"` - CheckPath *string `json:"checkPath" db:"check_path"` - DisplayName *string `json:"displayName" db:"display_name"` - DNSBypassCNAME *string `json:"dnsBypassCname" db:"dns_bypass_cname"` - DNSBypassIP *string `json:"dnsBypassIp" db:"dns_bypass_ip"` - DNSBypassIP6 *string `json:"dnsBypassIp6" db:"dns_bypass_ip6"` - DNSBypassTTL *int `json:"dnsBypassTtl" db:"dns_bypass_ttl"` - DSCP *int `json:"dscp" db:"dscp"` - EdgeHeaderRewrite *string `json:"edgeHeaderRewrite" db:"edge_header_rewrite"` - GeoLimit *int `json:"geoLimit" db:"geo_limit"` - GeoLimitCountries *string `json:"geoLimitCountries" db:"geo_limit_countries"` - GeoLimitRedirectURL *string `json:"geoLimitRedirectURL" db:"geolimit_redirect_url"` - GeoProvider *int `json:"geoProvider" db:"geo_provider"` - GlobalMaxMBPS *int `json:"globalMaxMbps" db:"global_max_mbps"` - GlobalMaxTPS *int `json:"globalMaxTps" db:"global_max_tps"` - HTTPBypassFQDN *string `json:"httpBypassFqdn" db:"http_bypass_fqdn"` - ID *int `json:"id" db:"id"` - InfoURL *string `json:"infoUrl" db:"info_url"` - InitialDispersion *int `json:"initialDispersion" db:"initial_dispersion"` - IPV6RoutingEnabled *bool `json:"ipv6RoutingEnabled" db:"ipv6_routing_enabled"` - LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"` - LogsEnabled *bool `json:"logsEnabled" db:"logs_enabled"` - LongDesc *string `json:"longDesc" db:"long_desc"` - LongDesc1 *string `json:"longDesc1,omitempty" db:"long_desc_1"` - LongDesc2 *string `json:"longDesc2,omitempty" db:"long_desc_2"` - MatchList *[]DeliveryServiceMatch `json:"matchList"` - MaxDNSAnswers *int `json:"maxDnsAnswers" db:"max_dns_answers"` - MidHeaderRewrite *string `json:"midHeaderRewrite" db:"mid_header_rewrite"` - MissLat *float64 `json:"missLat" db:"miss_lat"` - MissLong *float64 `json:"missLong" db:"miss_long"` - MultiSiteOrigin *bool `json:"multiSiteOrigin" db:"multi_site_origin"` - OriginShield *string `json:"originShield" db:"origin_shield"` - OrgServerFQDN *string `json:"orgServerFqdn" db:"org_server_fqdn"` - ProfileDesc *string `json:"profileDescription"` - ProfileID *int `json:"profileId" db:"profile"` - ProfileName *string `json:"profileName"` - Protocol *int `json:"protocol" db:"protocol"` - QStringIgnore *int `json:"qstringIgnore" db:"qstring_ignore"` - RangeRequestHandling *int `json:"rangeRequestHandling" db:"range_request_handling"` - RegexRemap *string `json:"regexRemap" db:"regex_remap"` - RegionalGeoBlocking *bool `json:"regionalGeoBlocking" db:"regional_geo_blocking"` - RemapText *string `json:"remapText" db:"remap_text"` - RoutingName *string `json:"routingName" db:"routing_name"` - Signed bool `json:"signed"` - SSLKeyVersion *int `json:"sslKeyVersion" db:"ssl_key_version"` - TenantID *int `json:"tenantId" db:"tenant_id"` - Type *DSType `json:"type"` - TypeID *int `json:"typeId" db:"type"` - XMLID *string `json:"xmlId" db:"xml_id"` - ExampleURLs []string `json:"exampleURLs"` -} - // DeliveryServiceRemovedFieldsV11 contains additions to delivery services in api v1.1 that were later removed // Deprecated: used for backwards compatibility with ATC Date: Wed, 7 Jul 2021 15:25:50 -0600 Subject: [PATCH 32/34] Fix not saving DS changes --- .../traffic_ops_golang/deliveryservice/deliveryservices.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 1a7c35f21a..2515fdc7fb 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -623,6 +623,8 @@ func createV40(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, dsV40 t return nil, http.StatusInternalServerError, nil, errors.New("error writing to audit log: " + err.Error()) } + dsV40 = ds + return &dsV40, http.StatusOK, nil, nil } From c768b144255a8be32582046967e3811e9af99bea Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 8 Jul 2021 12:14:20 -0600 Subject: [PATCH 33/34] Fix unit test failure --- .../traffic_ops_golang/deliveryservice/deliveryservices_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go index 41a9ed5004..5498c8ea30 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_test.go @@ -326,6 +326,7 @@ func TestReadGetDeliveryServices(t *testing.T) { "ssl_key_version", "tenant_id", "tenant.name", + "tls_versions", "topology", "tr_request_headers", "tr_response_headers", @@ -397,6 +398,7 @@ func TestReadGetDeliveryServices(t *testing.T) { nil, 1, "test", + "{}", nil, nil, nil, From 7b0b015fb668a6c18930c8e77a8a24dabdc1c63f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 8 Jul 2021 12:28:12 -0600 Subject: [PATCH 34/34] Fix integration test missing required DS fields --- traffic_ops/testing/api/v4/deliveryservices_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/traffic_ops/testing/api/v4/deliveryservices_test.go b/traffic_ops/testing/api/v4/deliveryservices_test.go index 563372f035..eda6ed26c6 100644 --- a/traffic_ops/testing/api/v4/deliveryservices_test.go +++ b/traffic_ops/testing/api/v4/deliveryservices_test.go @@ -2389,9 +2389,15 @@ func addTLSVersionsToDeliveryService(t *testing.T) { } var ds tc.DeliveryServiceV4 + ds.Active = new(bool) ds.CDNName = new(string) ds.DisplayName = new(string) + ds.DSCP = new(int) + ds.GeoLimit = new(int) + ds.GeoProvider = new(int) ds.InitialDispersion = new(int) + ds.IPV6RoutingEnabled = new(bool) + ds.LogsEnabled = new(bool) ds.MissLat = new(float64) ds.MissLong = new(float64) ds.MultiSiteOrigin = new(bool) @@ -2399,6 +2405,7 @@ func addTLSVersionsToDeliveryService(t *testing.T) { ds.Protocol = new(int) ds.QStringIgnore = new(int) ds.RangeRequestHandling = new(int) + ds.RegionalGeoBlocking = new(bool) ds.Tenant = new(string) ds.TenantID = me.Response.TenantID ds.TLSVersions = []string{ @@ -2406,6 +2413,7 @@ func addTLSVersionsToDeliveryService(t *testing.T) { } ds.Type = new(tc.DSType) ds.XMLID = new(string) + *ds.DSCP = 1 *ds.InitialDispersion = 1 *ds.Tenant = *me.Response.Tenant *ds.DisplayName = "ds-test-tls-versions"