[
https://issues.apache.org/jira/browse/TC-32?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15771183#comment-15771183
]
ASF GitHub Bot commented on TC-32:
----------------------------------
Github user mitchell852 commented on a diff in the pull request:
https://github.com/apache/incubator-trafficcontrol/pull/141#discussion_r93701822
--- Diff: traffic_ops/app/lib/API/Configs/ApacheTrafficServer.pm ---
@@ -0,0 +1,1959 @@
+package API::Configs::ApacheTrafficServer;
+
+#
+#
+# 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.
+#
+#
+#
+use UI::Utils;
+use Mojo::Base 'Mojolicious::Controller';
+use Date::Manip;
+use NetAddr::IP;
+use Data::Dumper;
+use UI::DeliveryService;
+use JSON;
+use API::DeliveryService::KeysUrlSig qw(URL_SIG_KEYS_BUCKET);
+use URI;
+use File::Basename;
+use File::Path;
+
+#Sub to generate ORT json
+sub ort {
+ my $self = shift;
+ my $id = $self->param('id');
+ my $filename = 'ort';
+ my $scope = 'server';
+
+ ##check user access
+ if ( !&is_oper($self) ) {
+ return $self->forbidden();
+ }
+
+ ##verify that a valid server ID has been used
+ my $server_obj = $self->server_data($id);
+ if ( !defined($server_obj) ) {
+ return $self->not_found();
+ }
+
+ my $data_obj;
+ my $host_name = $server_obj->host_name;
+
+ my %condition = ( 'me.host_name' => $host_name );
+ my $rs_profile = $self->db->resultset('Server')->search( \%condition, {
prefetch => [ 'cdn', 'profile' ] } );
+
+ my $row = $rs_profile->next;
+ if ($row) {
+ my $cdn_name = defined( $row->cdn_id ) ? $row->cdn->name : "";
+
+ $data_obj->{'profile'}->{'name'} = $row->profile->name;
+ $data_obj->{'profile'}->{'id'} = $row->profile->id;
+ $data_obj->{'other'}->{'CDN_name'} = $cdn_name;
+
+ %condition = (
+ 'profile_parameters.profile' =>
$data_obj->{'profile'}->{'id'},
+ -or => [ 'name' => 'location',
'name' => 'scope' ]
+ );
+ my $rs_config = $self->db->resultset('Parameter')->search(
\%condition, { join => 'profile_parameters' } );
+ while ( my $row = $rs_config->next ) {
+ if ( $row->name eq 'location' ) {
+ $data_obj->{'config_files'}->{
$row->config_file }->{'location'} = $row->value;
+ }
+ elsif ( $row->name eq 'scope' ) {
+ $data_obj->{'config_files'}->{
$row->config_file }->{'scope'} = $row->value;
+ }
+ }
+ }
+
+ foreach my $file ( keys %$data_obj->{'config_files'} ) {
+ if ( !defined( $data_obj->{'config_files'}->{$file}->{'scope'}
) ) {
+ $data_obj->{'config_files'}->{$file}->{'scope'} =
$self->get_scope($file);
+ }
+ }
+
+ my $file_contents = encode_json($data_obj);
+
+ return $self->render( text => $file_contents, format => 'txt' );
+}
+
+#entry point for server scope api route.
+sub get_server_config {
+ my $self = shift;
+ my $filename = $self->param("filename");
+ my $id = $self->param('id');
+ my $scope = $self->get_scope($filename);
+
+ ##check user access
+ if ( !&is_oper($self) ) {
+ return $self->forbidden();
+ }
+
+ ##check the scope - is this the correct route?
+ if ( $scope ne 'server' ) {
+ return $self->alert( "Error - incorrect file scope for route
used. Please use the " . $scope . " route." );
+ }
+
+ ##verify that a valid server ID has been used
+ my $server_obj = $self->server_data($id);
+ if ( !defined($server_obj) ) {
+ return $self->not_found();
+ }
+
+ #generate the config file using the appropriate function
+ my $file_contents;
+ if ( $filename eq "12M_facts" ) { $file_contents = $self->facts(
$server_obj, $filename, $scope ); }
+ elsif ( $filename =~ /to_ext_.*\.config/ ) { $file_contents =
$self->to_ext_dot_config( $server_obj, $filename, $scope ); }
+ elsif ( $filename eq "ip_allow.config" ) { $file_contents =
$self->ip_allow_dot_config( $server_obj, $filename, $scope ); }
+ elsif ( $filename eq "parent.config" ) { $file_contents =
$self->parent_dot_config( $server_obj, $filename, $scope ); }
+ elsif ( $filename eq "records.config" ) { $file_contents =
$self->generic_server_config( $server_obj, $filename, $scope ); }
+ elsif ( $filename eq "remap.config" ) { $file_contents =
$self->remap_dot_config( $server_obj, $filename, $scope ); }
+ elsif ( $filename eq "hosting.config" ) { $file_contents =
$self->hosting_dot_config( $server_obj, $filename, $scope ); }
+ elsif ( $filename eq "cache.config" ) { $file_contents =
$self->cache_dot_config( $server_obj, $filename, $scope ); }
+ elsif ( $filename eq "packages" ) {
+ $file_contents = $self->get_package_versions( $server_obj,
$filename, $scope );
+ $file_contents = encode_json($file_contents);
+ }
+ elsif ( $filename eq "chkconfig" ) {
+ $file_contents = $self->get_chkconfig( $server_obj, $filename,
$scope );
+ $file_contents = encode_json($file_contents);
+ }
+ else {
+ my $file_param = $self->db->resultset('Parameter')->search( [
config_file => $filename ] )->single;
+ if ( !defined($file_param) ) {
+ return $self->not_found();
+ }
+ $file_contents = $self->take_and_bake_server( $server_obj,
$filename, $scope );
+ }
+
+ #if we get an empty file, just send back an error.
+ if ( !defined($file_contents) ) {
+ return $self->not_found();
+ }
+
+ #return the file contents for fetch and db actions.
+ return $self->render( text => $file_contents, format => 'txt' );
+}
+
+#entry point for cdn scope api route.
+sub get_cdn_config {
+ my $self = shift;
+ my $filename = $self->param("filename");
+ my $id = $self->param('id');
+ my $scope = $self->get_scope($filename);
+
+ ##check user access
+ if ( !&is_oper($self) ) {
+ return $self->forbidden();
+ }
+ print STDERR "well i'm here anyway.";
+ ##check the scope - is this the correct route?
+ if ( $scope ne 'cdn' ) {
+ return $self->alert( "Error - incorrect file scope for route
used. Please use the " . $scope . " route." );
+ }
+
+ ##verify that a valid cdn ID has been used
+ my $cdn_obj = $self->cdn_data($id);
+ if ( !defined($cdn_obj) ) {
+ return $self->not_found();
+ }
+
+ #generate the config file using the appropriate function
+ my $file_contents;
+ if ( $filename eq "bg_fetch.config" ) { $file_contents =
$self->bg_fetch_dot_config( $cdn_obj, $filename, $scope ); }
+ elsif ( $filename =~ /cacheurl.*\.config/ ) { $file_contents =
$self->cacheurl_dot_config( $cdn_obj, $filename, $scope ); }
+ elsif ( $filename =~ /hdr_rw_.*\.config/ ) { $file_contents =
$self->header_rewrite_dot_config( $cdn_obj, $filename, $scope ); }
+ elsif ( $filename =~ /regex_remap_.*\.config/ ) { $file_contents =
$self->regex_remap_dot_config( $cdn_obj, $filename, $scope ); }
+ elsif ( $filename eq "regex_revalidate.config" ) { $file_contents =
$self->regex_revalidate_dot_config( $cdn_obj, $filename, $scope ); }
+ elsif ( $filename =~ /set_dscp_.*\.config/ ) { $file_contents =
$self->set_dscp_dot_config( $cdn_obj, $filename, $scope ); }
+ elsif ( $filename eq "ssl_multicert.config" ) { $file_contents =
$self->ssl_multicert_dot_config( $cdn_obj, $filename, $scope ); }
+ else { return
$self->not_found(); }
+
+ if ( !defined($file_contents) ) {
+ return $self->not_found();
+ }
+
+ return $self->render( text => $file_contents, format => 'txt' );
+}
+
+#entry point for profile scope api route.
+sub get_profile_config {
+ my $self = shift;
+ my $filename = $self->param("filename");
+ my $id = $self->param('id');
+ my $scope = $self->get_scope($filename);
+
+ ##check user access
+ if ( !&is_oper($self) ) {
+ return $self->forbidden();
+ }
+
+ ##check the scope - is this the correct route?
+ if ( $scope ne 'profile' ) {
+ return $self->alert( "Error - incorrect file scope for route
used. Please use the " . $scope . " route." );
+ }
+
+ ##verify that a valid profile ID has been used
+ my $profile_obj = $self->profile_data($id);
+ if ( !defined($profile_obj) ) {
+ return $self->not_found();
+ }
+
+ #generate the config file using the appropriate function
+ my $file_contents;
+ if ( $filename eq "50-ats.rules" ) { $file_contents =
$self->ats_dot_rules( $profile_obj, $filename, $scope ); }
+ elsif ( $filename eq "astats.config" ) { $file_contents =
$self->generic_profile_config( $profile_obj, $filename, $scope ); }
+ elsif ( $filename eq "drop_qstring.config" ) { $file_contents =
$self->drop_qstring_dot_config( $profile_obj, $filename, $scope ); }
+ elsif ( $filename eq "logs_xml.config" ) { $file_contents =
$self->logs_xml_dot_config( $profile_obj, $filename, $scope ); }
+ elsif ( $filename eq "plugin.config" ) { $file_contents =
$self->generic_profile_config( $profile_obj, $filename, $scope ); }
+ elsif ( $filename eq "storage.config" ) { $file_contents =
$self->storage_dot_config( $profile_obj, $filename, $scope ); }
+ elsif ( $filename eq "sysctl.conf" ) { $file_contents =
$self->generic_profile_config( $profile_obj, $filename, $scope ); }
+ elsif ( $filename =~ /url_sig_.*\.config/ ) { $file_contents =
$self->url_sig_dot_config( $profile_obj, $filename, $scope ); }
+ elsif ( $filename eq "volume.config" ) { $file_contents =
$self->volume_dot_config( $profile_obj, $filename, $scope ); }
+ else {
+ my $file_param = $self->db->resultset('Parameter')->search( [
config_file => $filename ] )->single;
+ if ( !defined($file_param) ) {
+ return $self->not_found();
+ }
+ $file_contents = $self->take_and_bake_profile( $profile_obj,
$filename, $scope );
+ }
+
+ if ( !defined($file_contents) ) {
+ return $self->not_found();
+ }
+
+ return $self->render( text => $file_contents, format => 'txt' );
+}
+
+my $separator ||= {
+ "records.config" => " ",
+ "plugin.config" => " ",
+ "sysctl.conf" => " = ",
+ "url_sig_.config" => " = ",
+ "astats.config" => "=",
+};
+
+#identify the correct scope for each filename. if not found, returns
server scope as any
+#undefined parameter based configs are designed with server scope using
the take-and-bake sub.
+sub get_scope {
+ my $self = shift;
+ my $fname = shift;
+ my $scope;
+
+ if ( $fname eq "12M_facts" ) { $scope = 'server' }
+ elsif ( $fname eq "ip_allow.config" ) { $scope = 'server' }
+ elsif ( $fname eq "parent.config" ) { $scope = 'server' }
+ elsif ( $fname eq "records.config" ) { $scope = 'server' }
+ elsif ( $fname eq "remap.config" ) { $scope = 'server' }
+ elsif ( $fname =~ /to_ext_.*\.config/ ) { $scope = 'server' }
+ elsif ( $fname eq "hosting.config" ) { $scope = 'server' }
+ elsif ( $fname eq "cache.config" ) { $scope = 'server' }
+ elsif ( $fname eq "packages" ) { $scope = 'server' }
+ elsif ( $fname eq "chkconfig" ) { $scope = 'server' }
+ elsif ( $fname eq "50-ats.rules" ) { $scope = 'profile' }
+ elsif ( $fname eq "astats.config" ) { $scope = 'profile' }
+ elsif ( $fname eq "drop_qstring.config" ) { $scope = 'profile' }
+ elsif ( $fname eq "logs_xml.config" ) { $scope = 'profile' }
+ elsif ( $fname eq "plugin.config" ) { $scope = 'profile' }
+ elsif ( $fname eq "storage.config" ) { $scope = 'profile' }
+ elsif ( $fname eq "sysctl.conf" ) { $scope = 'profile' }
+ elsif ( $fname =~ /url_sig_.*\.config/ ) { $scope = 'profile' }
+ elsif ( $fname eq "volume.config" ) { $scope = 'profile' }
+ elsif ( $fname eq "bg_fetch.config" ) { $scope = 'cdn' }
+ elsif ( $fname =~ /cacheurl.*\.config/ ) { $scope = 'cdn' }
+ elsif ( $fname =~ /hdr_rw_.*\.config/ ) { $scope = 'cdn' }
+ elsif ( $fname =~ /regex_remap_.*\.config/ ) { $scope = 'cdn' }
+ elsif ( $fname eq "regex_revalidate.config" ) { $scope = 'cdn' }
+ elsif ( $fname =~ /set_dscp_.*\.config/ ) { $scope = 'cdn' }
+ elsif ( $fname eq "ssl_multicert.config" ) { $scope = 'cdn' }
+ else {
+ $scope = $self->db->resultset('Parameter')->search( { -and => [
name => 'scope', config_file => $fname ] } )->get_column('value')->first();
+ if ( !defined($scope) ) {
+ $self->app->log->error("Filename not found. Setting
Server scope.");
+ $scope = 'server';
+ }
+ }
+
+ return $scope;
+}
+
+#takes the server name or ID and turns it into a server object that can
reference either, making either work for the request.
+sub server_data {
+ my $self = shift;
+ my $id = shift;
+
+ my $server_obj;
+
+ #if an ID is passed, look up by ID. Otherwise, look up by hostname.
+ if ( $id =~ /^\d+$/ ) {
+ $server_obj = $self->db->resultset('Server')->search( { id =>
$id } )->single;
+ }
+ else {
+ $server_obj = $self->db->resultset('Server')->search( {
host_name => $id } )->single;
+ }
+
+ return $server_obj;
+}
+
+#takes the profile name or ID and turns it into a server object that can
reference either, making either work for the request.
+sub profile_data {
+ my $self = shift;
+ my $id = shift;
+
+ #if an ID is passed, look up by ID. Otherwise, look up by profile name.
+ my $profile_obj;
+ if ( $id =~ /^\d+$/ ) {
+ $profile_obj = $self->db->resultset('Profile')->search( { id =>
$id } )->single;
+ }
+ else {
+ $profile_obj = $self->db->resultset('Profile')->search( { name
=> $id } )->single;
+ }
+
+ return $profile_obj;
+}
+
+#takes the server name or ID and turns it into a server object that can
reference either, making either work for the request.
+sub cdn_data {
+ my $self = shift;
+ my $id = shift;
+ my $cdn_obj;
+
+ if ( $id =~ /^\d+$/ ) {
+ $cdn_obj = $self->db->resultset('Cdn')->search( { id => $id }
)->single;
+ }
+ else {
+ $cdn_obj = $self->db->resultset('Cdn')->search( { name => $id }
)->single;
+ }
+
+ return $cdn_obj;
+}
+
+#generates the comment at the top of config files.
+sub header_comment {
+ my $self = shift;
+ my $name = shift;
+
+ my $text = "# DO NOT EDIT - Generated for " . $name . " by " .
&name_version_string($self) . " on " . `date`;
+ return $text;
+}
+
+#retrieves parameter data for a specific server by searching by the
server's assigned profile.
+sub param_data {
+ my $self = shift;
+ my $server_obj = shift;
+ my $filename = shift;
+ my $data;
+
+ my $rs = $self->db->resultset('ProfileParameter')->search( { -and => [
profile => $server_obj->profile->id, 'parameter.config_file' => $filename ] },
+ { prefetch => [ { parameter => undef }, { profile => undef } ]
} );
+ while ( my $row = $rs->next ) {
+ if ( $row->parameter->name eq "location" ) {
+ next;
+ }
+ if ( $row->parameter->name eq "scope" ) {
+ next;
+ }
+ my $value = $row->parameter->value;
+
+ # some files have multiple lines with the same key... handle
that with param id.
+ my $key = $row->parameter->name;
+ if ( defined( $data->{$key} ) ) {
+ $key .= "__" . $row->parameter->id;
+ }
+ if ( $value =~ /^STRING __HOSTNAME__$/ ) {
+ $value = "STRING " . $server_obj->host_name . "." .
$server_obj->domain_name;
+ }
+ $data->{$key} = $value;
+ }
+ return $data;
+}
+
+#retrieves parameter data for a specific profile by searching by the
profile id.
+sub profile_param_data {
+ my $self = shift;
+ my $profile = shift;
+ my $filename = shift;
+ my $data;
+
+ my $rs = $self->db->resultset('ProfileParameter')->search( { -and => [
profile => $profile, 'parameter.config_file' => $filename ] },
+ { prefetch => [ { parameter => undef }, { profile => undef } ]
} );
+ while ( my $row = $rs->next ) {
+ if ( $row->parameter->name eq "location" ) {
+ next;
+ }
+ if ( $row->parameter->name eq "scope" ) {
+ next;
+ }
+ my $value = $row->parameter->value;
+
+ # some files have multiple lines with the same key... handle
that with param id.
+ my $key = $row->parameter->name;
+ if ( defined( $data->{$key} ) ) {
+ $key .= "__" . $row->parameter->id;
+ }
+ $data->{$key} = $value;
+ }
+ return $data;
+}
+
+#searches for the a specific parameter by name in a specific profile by
profile ID and returns the data.
+sub profile_param_value {
+ my $self = shift;
+ my $pid = shift;
+ my $file = shift;
+ my $param_name = shift;
+ my $default = shift;
+
+ # assign $ds_domain, $weight and $port, and cache the results
%profile_cache
+ my $param =
+ $self->db->resultset('ProfileParameter')
+ ->search( { -and => [ profile => $pid, 'parameter.config_file'
=> $file, 'parameter.name' => $param_name ] },
+ { prefetch => [ 'parameter', 'profile' ] } )->first();
+
+ return ( defined $param ? $param->parameter->value : $default );
+}
+
+#gets the delivery service data for an entire CDN.
+sub cdn_ds_data {
+ my $self = shift;
+ my $id = shift;
+ my $dsinfo;
+
+ my $rs;
+ $rs = $self->db->resultset('DeliveryServiceInfoForCdnList')->search(
{}, { bind => [$id] } );
+
+ my $j = 0;
+ while ( my $row = $rs->next ) {
+ my $org_server = $row->org_server_fqdn;
+ my $dscp = $row->dscp;
+ my $re_type = $row->re_type;
+ my $ds_type = $row->ds_type;
+ my $signed = $row->signed;
+ my $qstring_ignore = $row->qstring_ignore;
+ my $ds_xml_id = $row->xml_id;
+ my $ds_domain = $row->domain_name;
+ my $edge_header_rewrite = $row->edge_header_rewrite;
+ my $mid_header_rewrite = $row->mid_header_rewrite;
+ my $regex_remap = $row->regex_remap;
+ my $protocol = $row->protocol;
+ my $range_request_handling = $row->range_request_handling;
+ my $origin_shield = $row->origin_shield;
+ my $cacheurl = $row->cacheurl;
+ my $remap_text = $row->remap_text;
+ my $multi_site_origin = $row->multi_site_origin;
+ my $multi_site_origin_algorithm =
$row->multi_site_origin_algorithm;
+
+ if ( $re_type eq 'HOST_REGEXP' && $ds_type ne 'ANY_MAP' ) {
+ my $host_re = $row->pattern;
+ my $map_to = $org_server . "/";
+ if ( $host_re =~ /\.\*$/ ) {
+ my $re = $host_re;
+ $re =~ s/\\//g;
+ $re =~ s/\.\*//g;
+ my $hname = $ds_type =~ /^DNS/ ? "edge" :
"ccr";
+ my $portstr = ":" . "SERVER_TCP_PORT";
+ my $map_from = "http://" . $hname . $re .
$ds_domain . $portstr . "/";
+ if ( $protocol == 0 ) {
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 1 || $protocol == 3 ) {
+ $map_from = "https://" . $hname . $re .
$ds_domain . "/";
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 2 ) {
+
+ #add the first one with http
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+
+ #add the second one for https
+ my $map_from2 = "https://" . $hname .
$re . $ds_domain . "/";
+
$dsinfo->{dslist}->[$j]->{"remap_line2"}->{$map_from2} = $map_to;
+ }
+ }
+ else {
+ my $map_from = "http://" . $host_re . "/";
+ if ( $protocol == 0 ) {
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 1 || $protocol == 3 ) {
+ $map_from = "https://" . $host_re . "/";
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 2 ) {
+
+ #add the first with http
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+
+ #add the second with https
+ my $map_from2 = "https://" . $host_re .
"/";
+
$dsinfo->{dslist}->[$j]->{"remap_line2"}->{$map_from2} = $map_to;
+ }
+ }
+ }
+
+ $dsinfo->{dslist}->[$j]->{"dscp"} =
$dscp;
+ $dsinfo->{dslist}->[$j]->{"org"} =
$org_server;
+ $dsinfo->{dslist}->[$j]->{"type"} =
$ds_type;
+ $dsinfo->{dslist}->[$j]->{"domain"} =
$ds_domain;
+ $dsinfo->{dslist}->[$j]->{"signed"} =
$signed;
+ $dsinfo->{dslist}->[$j]->{"qstring_ignore"} =
$qstring_ignore;
+ $dsinfo->{dslist}->[$j]->{"ds_xml_id"} =
$ds_xml_id;
+ $dsinfo->{dslist}->[$j]->{"edge_header_rewrite"} =
$edge_header_rewrite;
+ $dsinfo->{dslist}->[$j]->{"mid_header_rewrite"} =
$mid_header_rewrite;
+ $dsinfo->{dslist}->[$j]->{"regex_remap"} =
$regex_remap;
+ $dsinfo->{dslist}->[$j]->{"range_request_handling"} =
$range_request_handling;
+ $dsinfo->{dslist}->[$j]->{"origin_shield"} =
$origin_shield;
+ $dsinfo->{dslist}->[$j]->{"cacheurl"} =
$cacheurl;
+ $dsinfo->{dslist}->[$j]->{"remap_text"} =
$remap_text;
+ $dsinfo->{dslist}->[$j]->{"multi_site_origin"} =
$multi_site_origin;
+ $dsinfo->{dslist}->[$j]->{"multi_site_origin_algorithm"} =
$multi_site_origin_algorithm;
+
+ if ( defined($edge_header_rewrite) ) {
+ my $fname = "hdr_rw_" . $ds_xml_id . ".config";
+ $dsinfo->{dslist}->[$j]->{"hdr_rw_file"} = $fname;
+ }
+ if ( defined($mid_header_rewrite) ) {
+ my $fname = "hdr_rw_mid_" . $ds_xml_id . ".config";
+ $dsinfo->{dslist}->[$j]->{"mid_hdr_rw_file"} = $fname;
+ }
+ if ( defined($cacheurl) ) {
+ my $fname = "cacheurl_" . $ds_xml_id . ".config";
+ $dsinfo->{dslist}->[$j]->{"cacheurl_file"} = $fname;
+ }
+
+ $j++;
+ }
+
+ # $self->app->session->{dsinfo} = $dsinfo;
+ return $dsinfo;
+}
+
+#gets the delivery service data for a specific server.
+sub ds_data {
+ my $self = shift;
+ my $server_obj = shift;
+ my $dsinfo;
+
+ $dsinfo->{host_name} = $server_obj->host_name;
+ $dsinfo->{domain_name} = $server_obj->domain_name;
+
+ my @server_ids = ();
+ my $rs;
+ if ( $server_obj->type->name =~ m/^MID/ ) {
+
+ # the mids will do all deliveryservices in this CDN
+ my $domain = $self->profile_param_value(
$server_obj->profile->id, 'CRConfig.json', 'domain_name', '' );
+ $rs =
$self->db->resultset('DeliveryServiceInfoForDomainList')->search( {}, { bind =>
[$domain] } );
+ }
+ else {
+ $rs =
$self->db->resultset('DeliveryServiceInfoForServerList')->search( {}, { bind =>
[ $server_obj->id ] } );
+ }
+
+ my $j = 0;
+ while ( my $row = $rs->next ) {
+ my $org_server = $row->org_server_fqdn;
+ my $dscp = $row->dscp;
+ my $re_type = $row->re_type;
+ my $ds_type = $row->ds_type;
+ my $signed = $row->signed;
+ my $qstring_ignore = $row->qstring_ignore;
+ my $ds_xml_id = $row->xml_id;
+ my $ds_domain = $row->domain_name;
+ my $edge_header_rewrite = $row->edge_header_rewrite;
+ my $mid_header_rewrite = $row->mid_header_rewrite;
+ my $regex_remap = $row->regex_remap;
+ my $protocol = $row->protocol;
+ my $range_request_handling = $row->range_request_handling;
+ my $origin_shield = $row->origin_shield;
+ my $cacheurl = $row->cacheurl;
+ my $remap_text = $row->remap_text;
+ my $multi_site_origin = $row->multi_site_origin;
+ my $multi_site_origin_algorithm =
$row->multi_site_origin_algorithm;
+
+ if ( $re_type eq 'HOST_REGEXP' && $ds_type ne 'ANY_MAP' ) {
+ my $host_re = $row->pattern;
+ my $map_to = $org_server . "/";
+ if ( $host_re =~ /\.\*$/ ) {
+ my $re = $host_re;
+ $re =~ s/\\//g;
+ $re =~ s/\.\*//g;
+ my $hname = $ds_type =~ /^DNS/ ? "edge" : "ccr";
+ my $portstr = "";
+ if ( $hname eq "ccr" && $server_obj->tcp_port >
0 && $server_obj->tcp_port != 80 ) {
+ $portstr = ":" . $server_obj->tcp_port;
+ }
+ my $map_from = "http://" . $hname . $re .
$ds_domain . $portstr . "/";
+ if ( $protocol == 0 ) {
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 1 || $protocol == 3 ) {
+ $map_from = "https://" . $hname . $re .
$ds_domain . "/";
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 2 ) {
+
+ #add the first one with http
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+
+ #add the second one for https
+ my $map_from2 = "https://" . $hname .
$re . $ds_domain . "/";
+
$dsinfo->{dslist}->[$j]->{"remap_line2"}->{$map_from2} = $map_to;
+ }
+ }
+ else {
+ my $map_from = "http://" . $host_re . "/";
+ if ( $protocol == 0 ) {
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 1 || $protocol == 3 ) {
+ $map_from = "https://" . $host_re . "/";
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+ }
+ elsif ( $protocol == 2 ) {
+
+ #add the first with http
+
$dsinfo->{dslist}->[$j]->{"remap_line"}->{$map_from} = $map_to;
+
+ #add the second with https
+ my $map_from2 = "https://" . $host_re .
"/";
+
$dsinfo->{dslist}->[$j]->{"remap_line2"}->{$map_from2} = $map_to;
+ }
+ }
+ }
+ $dsinfo->{dslist}->[$j]->{"dscp"} =
$dscp;
+ $dsinfo->{dslist}->[$j]->{"org"} =
$org_server;
+ $dsinfo->{dslist}->[$j]->{"type"} =
$ds_type;
+ $dsinfo->{dslist}->[$j]->{"domain"} =
$ds_domain;
+ $dsinfo->{dslist}->[$j]->{"signed"} =
$signed;
+ $dsinfo->{dslist}->[$j]->{"qstring_ignore"} =
$qstring_ignore;
+ $dsinfo->{dslist}->[$j]->{"ds_xml_id"} =
$ds_xml_id;
+ $dsinfo->{dslist}->[$j]->{"edge_header_rewrite"} =
$edge_header_rewrite;
+ $dsinfo->{dslist}->[$j]->{"mid_header_rewrite"} =
$mid_header_rewrite;
+ $dsinfo->{dslist}->[$j]->{"regex_remap"} =
$regex_remap;
+ $dsinfo->{dslist}->[$j]->{"range_request_handling"} =
$range_request_handling;
+ $dsinfo->{dslist}->[$j]->{"origin_shield"} =
$origin_shield;
+ $dsinfo->{dslist}->[$j]->{"cacheurl"} =
$cacheurl;
+ $dsinfo->{dslist}->[$j]->{"remap_text"} =
$remap_text;
+ $dsinfo->{dslist}->[$j]->{"multi_site_origin"} =
$multi_site_origin;
+ $dsinfo->{dslist}->[$j]->{"multi_site_origin_algorithm"} =
$multi_site_origin_algorithm;
+
+ if ( defined($edge_header_rewrite) ) {
+ my $fname = "hdr_rw_" . $ds_xml_id . ".config";
+ $dsinfo->{dslist}->[$j]->{"hdr_rw_file"} = $fname;
+ }
+ if ( defined($mid_header_rewrite) ) {
+ my $fname = "hdr_rw_mid_" . $ds_xml_id . ".config";
+ $dsinfo->{dslist}->[$j]->{"mid_hdr_rw_file"} = $fname;
+ }
+ if ( defined($cacheurl) ) {
+ my $fname = "cacheurl_" . $ds_xml_id . ".config";
+ $dsinfo->{dslist}->[$j]->{"cacheurl_file"} = $fname;
+ }
+
+ $j++;
+ }
+
+ return $dsinfo;
+}
+
+#generates the 12m_facts file
+sub facts {
+ my $self = shift;
+ my $server_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+ my $text = $self->header_comment( $server_obj->host_name );
+ $text .= "profile:" . $server_obj->profile->name . "\n";
+
+ return $text;
+}
+
+#generates a generic config file based on a server and parameters which
match the supplied filename.
+sub take_and_bake_server {
+ my $self = shift;
+ my $server_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $data = $self->param_data( $server_obj, $filename );
+ my $text = $self->header_comment( $server_obj->host_name );
+ foreach my $parameter ( sort keys %{$data} ) {
+ $text .= $data->{$parameter} . "\n";
+ }
+ return $text;
+}
+
+#generates a generic config file based on a profile and parameters which
match the supplied filename.
+sub take_and_bake_profile {
+ my $self = shift;
+ my $profile_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $data = $self->profile_param_data( $profile_obj->id, $filename );
+ my $text = $self->header_comment( $profile_obj->name );
+ foreach my $parameter ( sort keys %{$data} ) {
+ $text .= $data->{$parameter} . "\n";
+ }
+ return $text;
+}
+
+#generates a generic config file based on a profile and parameters which
match the supplied filename.
+#differs from take and bake in that it uses predefined separators.
+sub generic_profile_config {
+ my $self = shift;
+ my $profile_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $sep = defined( $separator->{$filename} ) ? $separator->{$filename}
: " = ";
+
+ my $data = $self->profile_param_data( $profile_obj->id, $filename );
+ my $text = $self->header_comment( $profile_obj->name );
+ foreach my $parameter ( sort keys %{$data} ) {
+ my $p_name = $parameter;
+ $p_name =~ s/__\d+$//;
+ $text .= $p_name . $sep . $data->{$parameter} . "\n";
+ }
+
+ return $text;
+}
+
+#generates a generic config file based on a server and parameters which
match the supplied filename.
+#differs from take and bake in that it uses predefined separators.
+sub generic_server_config {
+ my $self = shift;
+ my $server_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $sep = defined( $separator->{$filename} ) ? $separator->{$filename}
: " = ";
+
+ my $data = $self->param_data( $server_obj, $filename );
+ my $text = $self->header_comment( $server_obj->host_name );
+ foreach my $parameter ( sort keys %{$data} ) {
+ my $p_name = $parameter;
+ $p_name =~ s/__\d+$//;
+ $text .= $p_name . $sep . $data->{$parameter} . "\n";
+ }
+
+ return $text;
+}
+
+sub ats_dot_rules {
+ my $self = shift;
+ my $profile_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $profile_obj->name );
+ my $data = $self->profile_param_data( $profile_obj->id,
"storage.config" ); # ats.rules is based on the storage.config params
+
+ my $drive_prefix = $data->{Drive_Prefix};
+ my @drive_postfix = split( /,/, $data->{Drive_Letters} );
+ foreach my $l ( sort @drive_postfix ) {
+ $drive_prefix =~ s/\/dev\///;
+ $text .= "KERNEL==\"" . $drive_prefix . $l . "\",
OWNER=\"ats\"\n";
+ }
+ if ( defined( $data->{RAM_Drive_Prefix} ) ) {
+ $drive_prefix = $data->{RAM_Drive_Prefix};
+ @drive_postfix = split( /,/, $data->{RAM_Drive_Letters} );
+ foreach my $l ( sort @drive_postfix ) {
+ $drive_prefix =~ s/\/dev\///;
+ $text .= "KERNEL==\"" . $drive_prefix . $l . "\",
OWNER=\"ats\"\n";
+ }
+ }
+
+ return $text;
+}
+
+sub drop_qstring_dot_config {
+ my $self = shift;
+ my $profile_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $profile_obj->name );
+
+ my $drop_qstring = $self->profile_param_value( $profile_obj->id,
'drop_qstring.config', 'content', undef );
+
+ if ($drop_qstring) {
+ $text .= $drop_qstring . "\n";
+ }
+ else {
+ $text .= "/([^?]+) \$s://\$t/\$1\n";
+ }
+
+ return $text;
+}
+
+sub logs_xml_dot_config {
+ my $self = shift;
+ my $profile_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $data = $self->profile_param_data( $profile_obj->id,
"logs_xml.config" );
+ my $text = $self->header_comment( $profile_obj->name );
+
+ my $log_format_name = $data->{"LogFormat.Name"}
|| "";
+ my $log_object_filename = $data->{"LogObject.Filename"}
|| "";
+ my $log_object_format = $data->{"LogObject.Format"}
|| "";
+ my $log_object_rolling_enabled =
$data->{"LogObject.RollingEnabled"} || "";
+ my $log_object_rolling_interval_sec =
$data->{"LogObject.RollingIntervalSec"} || "";
+ my $log_object_rolling_offset_hr =
$data->{"LogObject.RollingOffsetHr"} || "";
+ my $log_object_rolling_size_mb =
$data->{"LogObject.RollingSizeMb"} || "";
+ my $format = $data->{"LogFormat.Format"};
+ $format =~ s/"/\\\"/g;
+ $text .= "<LogFormat>\n";
+ $text .= " <Name = \"" . $log_format_name . "\"/>\n";
+ $text .= " <Format = \"" . $format . "\"/>\n";
+ $text .= "</LogFormat>\n";
+ $text .= "<LogObject>\n";
+ $text .= " <Format = \"" . $log_object_format . "\"/>\n";
+ $text .= " <Filename = \"" . $log_object_filename . "\"/>\n";
+ $text .= " <RollingEnabled = " . $log_object_rolling_enabled . "/>\n"
unless defined();
+ $text .= " <RollingIntervalSec = " . $log_object_rolling_interval_sec
. "/>\n";
+ $text .= " <RollingOffsetHr = " . $log_object_rolling_offset_hr .
"/>\n";
+ $text .= " <RollingSizeMb = " . $log_object_rolling_size_mb . "/>\n";
+ $text .= "</LogObject>\n";
+
+ return $text;
+}
+
+sub storage_dot_config_volume_text {
+ my $prefix = shift;
+ my $letters = shift;
+ my $volume = shift;
+
+ my $text = "";
+ my @postfix = split( /,/, $letters );
+ foreach my $l ( sort @postfix ) {
+ $text .= $prefix . $l;
+ $text .= " volume=" . $volume;
+ $text .= "\n";
+ }
+ return $text;
+}
+
+sub storage_dot_config {
+ my $self = shift;
+ my $profile_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $profile_obj->name );
+ my $data = $self->profile_param_data( $profile_obj->id,
"storage.config" );
+
+ my $next_volume = 1;
+ if ( defined( $data->{Drive_Prefix} ) ) {
+ $text .= storage_dot_config_volume_text( $data->{Drive_Prefix},
$data->{Drive_Letters}, $next_volume );
+ $next_volume++;
+ }
+
+ if ( defined( $data->{RAM_Drive_Prefix} ) ) {
+ $text .= storage_dot_config_volume_text(
$data->{RAM_Drive_Prefix}, $data->{RAM_Drive_Letters}, $next_volume );
+ $next_volume++;
+ }
+
+ if ( defined( $data->{SSD_Drive_Prefix} ) ) {
+ $text .= storage_dot_config_volume_text(
$data->{SSD_Drive_Prefix}, $data->{SSD_Drive_Letters}, $next_volume );
+ $next_volume++;
+ }
+
+ return $text;
+}
+
+sub to_ext_dot_config {
+ my $self = shift;
+ my $server_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $server_obj->host_name );
+
+ # get the subroutine name for this file from the parameter
+ my $subroutine = $self->profile_param_value( $server_obj->profile->id,
$filename, 'SubRoutine', undef );
+ $self->app->log->error( "ToExtDotConfigFile == " . $subroutine );
+
+ if ( defined $subroutine ) {
+ my $package;
+ ( $package = $subroutine ) =~ s/(.*)(::)(.*)/$1/;
+ eval "use $package;";
+
+ # And call it - the below calls the subroutine in the var
$subroutine.
+ no strict 'refs';
+ $text .= $subroutine->( $self, $server_obj->host_name,
$filename );
+ return $text;
+ }
+ else {
+ return;
+ }
+}
+
+sub get_num_volumes {
+ my $data = shift;
+
+ my $num = 0;
+ my @drive_prefixes = qw( Drive_Prefix SSD_Drive_Prefix
RAM_Drive_Prefix);
+ foreach my $pre (@drive_prefixes) {
+ if ( exists $data->{$pre} ) {
+ $num++;
+ }
+ }
+ return $num;
+}
+
+sub volume_dot_config_volume_text {
+ my $volume = shift;
+ my $num_volumes = shift;
+ my $size = int( 100 / $num_volumes );
+ return "volume=$volume scheme=http size=$size%\n";
+}
+
+sub volume_dot_config {
+ my $self = shift;
+ my $profile_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $data = $self->profile_param_data( $profile_obj->id,
"storage.config" );
+ my $text = $self->header_comment( $profile_obj->name );
+
+ my $num_volumes = get_num_volumes($data);
+
+ my $next_volume = 1;
+ $text .= "# 12M NOTE: This is running with forced volumes - the size is
irrelevant\n";
+ if ( defined( $data->{Drive_Prefix} ) ) {
+ $text .= volume_dot_config_volume_text( $next_volume,
$num_volumes );
+ $next_volume++;
+ }
+ if ( defined( $data->{RAM_Drive_Prefix} ) ) {
+ $text .= volume_dot_config_volume_text( $next_volume,
$num_volumes );
+ $next_volume++;
+ }
+ if ( defined( $data->{SSD_Drive_Prefix} ) ) {
+ $text .= volume_dot_config_volume_text( $next_volume,
$num_volumes );
+ $next_volume++;
+ }
+
+ return $text;
+}
+
+# This is a temporary workaround until we have real partial object caching
support in ATS, so hardcoding for now
+sub bg_fetch_dot_config {
+ my $self = shift;
+ my $cdn_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $cdn_obj->name );
+ $text .= "include User-Agent *\n";
+
+ return $text;
+}
+
+sub header_rewrite_dot_config {
+ my $self = shift;
+ my $cdn_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $cdn_obj->name );
+ my $ds_xml_id = undef;
+ if ( $filename =~ /^hdr_rw_mid_(.*)\.config$/ ) {
+ $ds_xml_id = $1;
+ my $ds = $self->db->resultset('Deliveryservice')->search( {
xml_id => $ds_xml_id }, { prefetch => [ 'type', 'profile' ] } )->first();
+ my $actions = $ds->mid_header_rewrite;
+ $text .= $actions . "\n";
+ }
+ elsif ( $filename =~ /^hdr_rw_(.*)\.config$/ ) {
+ $ds_xml_id = $1;
+ my $ds = $self->db->resultset('Deliveryservice')->search( {
xml_id => $ds_xml_id }, { prefetch => [ 'type', 'profile' ] } )->first();
+ my $actions = $ds->edge_header_rewrite;
+ $text .= $actions . "\n";
+ }
+
+ $text =~ s/\s*__RETURN__\s*/\n/g;
+
+ return $text;
+}
+
+sub cacheurl_dot_config {
+ my $self = shift;
+ my $cdn_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $cdn_obj->name );
+ my $data = $self->cdn_ds_data( $cdn_obj->id );
+
+ if ( $filename eq "cacheurl_qstring.config" ) { # This is the per
remap drop qstring w cacheurl use case, the file is the same for all remaps
+ $text .= "http://([^?]+)(?:\\?|\$) http://\$1\n";
+ $text .= "https://([^?]+)(?:\\?|\$) https://\$1\n";
+ }
+ elsif ( $filename =~ /cacheurl_(.*).config/ )
+ { # Yes, it's possibe to have the same plugin invoked multiple times
on the same remap line, this is from the remap entry
+ my $ds_xml_id = $1;
+ my $ds = $self->db->resultset('Deliveryservice')->search( {
xml_id => $ds_xml_id }, { prefetch => [ 'type', 'profile' ] } )->first();
+ if ($ds) {
+ $text .= $ds->cacheurl . "\n";
+ }
+ }
+ elsif ( $filename eq "cacheurl.config" ) { # this is the global drop
qstring w cacheurl use case
+ foreach my $remap ( @{ $data->{dslist} } ) {
+ if ( $remap->{qstring_ignore} == 1 ) {
+ my $org = $remap->{org};
+ $org =~ /(https?:\/\/)(.*)/;
+ $text .= "$1(" . $2 . "/[^?]+)(?:\\?|\$)
$1\$1\n";
+ }
+ }
+
+ }
+
+ $text =~ s/\s*__RETURN__\s*/\n/g;
+
+ return $text;
+}
+
+sub regex_remap_dot_config {
+ my $self = shift;
+ my $cdn_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = $self->header_comment( $cdn_obj->name );
+
+ if ( $filename =~ /^regex_remap_(.*)\.config$/ ) {
+ my $ds_xml_id = $1;
+ my $ds = $self->db->resultset('Deliveryservice')->search( {
xml_id => $ds_xml_id }, { prefetch => [ 'type', 'profile' ] } )->first();
+ $text .= $ds->regex_remap . "\n";
+ }
+
+ $text =~ s/\s*__RETURN__\s*/\n/g;
+
+ return $text;
+}
+
+sub regex_revalidate_dot_config {
+ my $self = shift;
+ my $cdn_obj = shift;
+ my $filename = shift;
+ my $scope = shift;
+
+ my $text = "# DO NOT EDIT - Generated for CDN " . $cdn_obj->name . " by
" . &name_version_string($self) . " on " . `date`;
+
+ my $max_days =
+ $self->db->resultset('Parameter')->search( { name =>
"maxRevalDurationDays" }, { config_file => "regex_revalidate.config" }
)->get_column('value')
+ ->single;
+ my $interval = "> now() - interval '$max_days day'";
+
+ my %regex_time;
+ $max_days =
--- End diff --
this query was already run
> Improve efficiency of ATS config generation
> -------------------------------------------
>
> Key: TC-32
> URL: https://issues.apache.org/jira/browse/TC-32
> Project: Traffic Control
> Issue Type: Improvement
> Components: Traffic Ops API
> Reporter: Derek Gelinas
> Assignee: Derek Gelinas
> Fix For: 1.9.0
>
>
> Currently when generating ATS configuration files, each server calls for its
> individual files from traffic ops. This is a very database-intensive process
> that is not scalable enough. I propose the following changes:
> 1) Generate the configuration files only as many times as needed - many files
> are the same (or can be) for the entire CDN or server profile.
> 2) Once generated, the files can be cached locally. Requests for the files
> by ORT will result in pulling down these cached files rather than many
> hundreds of DB queries each time.
> 3) Migrate the routes for these files to the API. Each call will have
> multiple options - a request made with no options would return the cached
> file, another option would return the current DB data, and a third option
> would update the cached file with the current information in the DB.
> 4) When an update is queued, generate and cache the configuration files, then
> activate the update flag for the relevant servers once the cached file
> generation is completed.
> In this way, triggering updates for the caches will result in an initial
> increase in activity as traffic ops generates the files needed, followed by
> the much lower impact of the files themselves being requested by the caches.
> I believe we can cut down the number of server-specific configuration files
> to only 5 intially, and potentially fewer by having ORT fill in certain
> fields on files like records.config with local data during processing.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)