use REST::Client;
use Data::Dumper;
use FS::Conf;
+use Carp qw(carp);
=pod
sub _export_insert {
my ($self, $svc_broadband) = @_;
- my $service_part = FS::Record::qsearchs( 'part_svc', { 'svcpart' => $svc_broadband->{Hash}->{svcpart} } );
- my $rateplan_name = $service_part->{Hash}->{svc};
- $rateplan_name =~ s/\s/_/g;
+ my $rateplan_name = $self->get_rateplan_name($svc_broadband);
# check for existing rate plan
my $existing_rateplan;
my $accesspoint = process_sector($self, $sector_opt);
return $self->api_error if $self->{'__saisei_error'};
+## get custnum and pkgpart from cust_pkg for virtual access point
+ my $cust_pkg = FS::Record::qsearchs({
+ 'table' => 'cust_pkg',
+ 'hashref' => { 'pkgnum' => $svc_broadband->{Hash}->{pkgnum}, },
+ });
+ my $virtual_ap_name = $cust_pkg->{Hash}->{custnum}.'_'.$cust_pkg->{Hash}->{pkgpart}.'_'.$svc_broadband->{Hash}->{speed_down}.'_'.$svc_broadband->{Hash}->{speed_up};
+
+ my $virtual_ap_opt = {
+ 'virtual_name' => $virtual_ap_name,
+ 'sector_name' => $sector_name,
+ 'virtual_uprate_limit' => $svc_broadband->{Hash}->{speed_up},
+ 'virtual_downrate_limit' => $svc_broadband->{Hash}->{speed_down},
+ };
+ my $virtual_ap = process_virtual_ap($self, $virtual_ap_opt);
+ return $self->api_error if $self->{'__saisei_error'};
+
## tie host to user add sector name as access point.
$self->api_add_host_to_user(
$user->{collection}->[0]->{name},
$rateplan->{collection}->[0]->{name},
$svc_broadband->{Hash}->{ip_addr},
- $accesspoint->{collection}->[0]->{name},
+ $virtual_ap->{collection}->[0]->{name},
) unless $self->{'__saisei_error'};
}
sub _export_replace {
my ($self, $svc_broadband) = @_;
- return '';
+ my $error = $self->_export_insert($svc_broadband);
+ return $error;
}
sub _export_delete {
my ($self, $svc_broadband) = @_;
- my $service_part = FS::Record::qsearchs( 'part_svc', { 'svcpart' => $svc_broadband->{Hash}->{svcpart} } );
- my $rateplan_name = $service_part->{Hash}->{svc};
- $rateplan_name =~ s/\s/_/g;
+ my $rateplan_name = $self->get_rateplan_name($svc_broadband);
+
my $username = $svc_broadband->{Hash}->{svcnum};
## untie host to user
sub export_partsvc {
my ($self, $svc_part) = @_;
- my $rateplan_name = $svc_part->{Hash}->{svc};
- $rateplan_name =~ s/\s/_/g;
- my $speeddown = $svc_part->{Hash}->{svc_broadband__speed_down};
- my $speedup = $svc_part->{Hash}->{svc_broadband__speed_up};
+ if ( $FS::svc_Common::noexport_hack ) {
+ carp 'export_partsvc() suppressed by noexport_hack'
+ if $self->option('debug');
+ return;
+ }
- my $temp_svc = $svc_part->{Hash};
- my $svc_broadband = {};
- map { if ($_ =~ /^svc_broadband__(.*)$/) { $svc_broadband->{Hash}->{$1} = $temp_svc->{$_}; } } keys %$temp_svc;
+ my $fcc_477_speeds;
+ if ($svc_part->{Hash}->{svc_broadband__speed_down} eq "down" || $svc_part->{Hash}->{svc_broadband__speed_up} eq "up") {
+ for my $type (qw( down up )) {
+ my $speed_type = "broadband_".$type."stream";
+ foreach my $pkg_svc (FS::Record::qsearch({
+ 'table' => 'pkg_svc',
+ 'select' => 'pkg_svc.*, part_pkg_fcc_option.fccoptionname, part_pkg_fcc_option.optionvalue',
+ 'addl_from' => ' LEFT JOIN part_pkg_fcc_option USING (pkgpart) ',
+ 'extra_sql' => " WHERE pkg_svc.svcpart = ".$svc_part->{Hash}->{svcpart}." AND pkg_svc.quantity > 0 AND part_pkg_fcc_option.fccoptionname = '".$speed_type."'",
+ })) { $fcc_477_speeds->{
+ $pkg_svc->{Hash}->{pkgpart}}->{$speed_type} = $pkg_svc->{Hash}->{optionvalue} * 1000 unless !$pkg_svc->{Hash}->{optionvalue}; }
+ }
+ }
+ else {
+ $fcc_477_speeds->{1}->{broadband_downstream} = $svc_part->{Hash}->{"svc_broadband__speed_down"};
+ $fcc_477_speeds->{1}->{broadband_upstream} = $svc_part->{Hash}->{"svc_broadband__speed_up"};
+ }
- # check for existing rate plan
- my $existing_rateplan;
- $existing_rateplan = $self->api_get_rateplan($rateplan_name) unless $self->{'__saisei_error'};
+ foreach my $key (keys %$fcc_477_speeds) {
- # Modify the existing rate plan with new service data.
- $self->api_modify_existing_rateplan($svc_broadband, $rateplan_name) unless ($self->{'__saisei_error'} || !$existing_rateplan);
+ $svc_part->{Hash}->{speed_down} = $fcc_477_speeds->{$key}->{broadband_downstream};
+ $svc_part->{Hash}->{speed_up} = $fcc_477_speeds->{$key}->{broadband_upstream};
+ $svc_part->{Hash}->{svc_broadband__speed_down} = $fcc_477_speeds->{$key}->{broadband_downstream};
+ $svc_part->{Hash}->{svc_broadband__speed_up} = $fcc_477_speeds->{$key}->{broadband_upstream};
- # if no existing rate plan create one and modify it.
- $self->api_create_rateplan($svc_broadband, $rateplan_name) unless $existing_rateplan;
- $self->api_modify_rateplan($svc_part, $rateplan_name) unless ($self->{'__saisei_error'} || $existing_rateplan);
+ my $temp_svc = $svc_part->{Hash};
+ my $svc_broadband = {};
+ map { if ($_ =~ /^svc_broadband__(.*)$/) { $svc_broadband->{Hash}->{$1} = $temp_svc->{$_}; } } keys %$temp_svc;
+
+ my $rateplan_name = $self->get_rateplan_name($svc_broadband, $svc_part->{Hash}->{svc});
+
+ # check for existing rate plan
+ my $existing_rateplan;
+ $existing_rateplan = $self->api_get_rateplan($rateplan_name) unless $self->{'__saisei_error'};
+
+ # Modify the existing rate plan with new service data.
+ $self->api_modify_existing_rateplan($svc_broadband, $rateplan_name) unless ($self->{'__saisei_error'} || !$existing_rateplan);
+
+ # if no existing rate plan create one and modify it.
+ $self->api_create_rateplan($svc_broadband, $rateplan_name) unless $existing_rateplan;
+ $self->api_modify_rateplan($svc_part, $rateplan_name) unless ($self->{'__saisei_error'} || $existing_rateplan);
+
+ }
return $self->api_error;
sub export_tower_sector {
my ($self, $tower) = @_;
+ if ( $FS::svc_Common::noexport_hack ) {
+ carp 'export_tower_sector() suppressed by noexport_hack'
+ if $self->option('debug');
+ return;
+ }
+
#modify tower or create it.
my $tower_name = $tower->{Hash}->{towername};
$tower_name =~ s/\s/_/g;
};
my $tower_access_point = process_tower($self, $tower_opt);
+ return $tower_access_point if $tower_access_point->{error};
#get list of all access points
my $hash_opt = {
'modify_existing' => '1', # modify an existing access point with this info
};
my $sector_access_point = process_sector($self, $sector_opt);
+ return $sector_access_point if $sector_access_point->{error};
}
return $self->api_error;
}
+## creates the rateplan name
+sub get_rateplan_name {
+ my ($self, $svc_broadband, $svc_name) = @_;
+
+ my $service_part = FS::Record::qsearchs( 'part_svc', { 'svcpart' => $svc_broadband->{Hash}->{svcpart} } ) unless $svc_name;
+ my $service_name = $svc_name ? $svc_name : $service_part->{Hash}->{svc};
+
+ my $rateplan_name = $service_name . " " . $svc_broadband->{Hash}->{speed_down} . "-" . $svc_broadband->{Hash}->{speed_up};
+ $rateplan_name =~ s/\s/_/g;
+
+ return $rateplan_name;
+}
+
=head1 Saisei API
These methods allow access to the Saisei API using the credentials
warn "Calling $method on http://"
.$self->{Hash}->{machine}.':'.$self->option('port')
- ."/rest/stm/configurations/running/$path\n" if $self->option('debug');
+ ."/rest/top/configurations/running/$path\n" if $self->option('debug');
my $data = encode_json($params) if keys %{ $params };
my $client = REST::Client->new();
$client->addHeader("Authorization", "Basic ".encode_base64($auth_info));
$client->setHost('http://'.$self->{Hash}->{machine}.':'.$self->option('port'));
- $client->$method('/rest/stm/configurations/running'.$path, $data, { "Content-type" => 'application/json'});
+ $client->$method('/rest/top/configurations/running'.$path, $data, { "Content-type" => 'application/json'});
warn "Response Code is ".$client->responseCode()."\n" if $self->option('debug');
return;
}
}
+ elsif ($client->responseCode() eq '404') {
+ eval { $result = decode_json($client->responseContent()) };
+ unless ($result) {
+ $self->{'__saisei_error'} = "Error decoding json: $@";
+ return;
+ }
+ ## check if message is for empty hash.
+ my($does_not_exist) = $result->{message} =~ /'(.*)' does not exist$/;
+ $self->{'__saisei_error'} = "Error ".$result->{message} unless $does_not_exist;
+ warn "Response Content is\n".$client->responseContent."\n" if ($self->option('debug') && !$does_not_exist);
+ return;
+ }
+ elsif ($client->responseCode() eq '500') {
+ $self->{'__saisei_error'} = "Can't connect to host during $method , received responce code: " . $client->responseCode() . " and message: " . $client->responseContent();
+ warn "Response Content is\n".$client->responseContent."\n" if $self->option('debug');
+ return;
+ }
else {
- $self->{'__saisei_error'} = "Bad response from server during $method: " . $client->responseContent()
- unless ($method eq "GET");
+ $self->{'__saisei_error'} = "Bad response from server during $method , received responce code: " . $client->responseCode() . " and message: " . $client->responseContent();
warn "Response Content is\n".$client->responseContent."\n" if $self->option('debug');
return;
}
my $get_host = $self->api_call("GET", "/hosts/$ip");
- return if $self->api_error;
+ return $self->api_error if $self->api_error;
return $get_host;
}
sub api_create_accesspoint {
my ($self,$accesspoint, $upratelimit, $downratelimit) = @_;
- # this has not been tested, but should work, if needed.
my $new_accesspoint = $self->api_call(
"PUT",
"/access_points/$accesspoint",
sub process_tower {
my ($self, $opt) = @_;
+ if (!$opt->{tower_uprate_limit} || !$opt->{tower_downrate_limit}) {
+ $self->{'__saisei_error'} = "Can not export tower, no up or down rates attached to tower";
+ return { error => $self->api_error, };
+ }
+
my $existing_tower_ap;
my $tower_name = $opt->{tower_name};
'', # tower does not have a uplink on sectors.
$opt->{tower_uprate_limit},
$opt->{tower_downrate_limit},
- ) if $existing_tower_ap && $opt->{modify_existing};
+ ) if $existing_tower_ap->{collection} && $opt->{modify_existing};
#if tower does not exist as an access point create it.
$self->api_create_accesspoint(
$tower_name,
$opt->{tower_uprate_limit},
- $opt->{tower_downrate_limit}
- ) unless $existing_tower_ap;
+ $opt->{tower_downrate_limit},
+ ) unless $existing_tower_ap->{collection};
my $accesspoint = $self->api_get_accesspoint($tower_name);
sub process_sector {
my ($self, $opt) = @_;
+ if (!$opt->{sector_uprate_limit} || !$opt->{sector_downrate_limit}) {
+ $self->{'__saisei_error'} = "Can not export sector, no up or down rates attached to sector";
+ return { error => $self->api_error, };
+ }
+
my $existing_sector_ap;
my $sector_name = $opt->{sector_name};
return $accesspoint;
}
+sub process_virtual_ap {
+ my ($self, $opt) = @_;
+
+ my $existing_virtual_ap;
+ my $virtual_name = $opt->{virtual_name};
+
+ #check if virtual_ap has been set up as an access point.
+ $existing_virtual_ap = $self->api_get_accesspoint($virtual_name);
+
+ # modify the existing virtual accesspoint if changing it. this should never happen
+ $self->api_modify_existing_accesspoint (
+ $virtual_name,
+ $opt->{sector_name},
+ $opt->{virtual_uprate_limit},
+ $opt->{virtual_downrate_limit},
+ ) if $existing_virtual_ap && $opt->{modify_existing};
+
+ #if virtual ap does not exist as an access point create it.
+ $self->api_create_accesspoint(
+ $virtual_name,
+ $opt->{virtual_uprate_limit},
+ $opt->{virtual_downrate_limit},
+ ) unless $existing_virtual_ap;
+
+ my $update_sector;
+ if ($existing_virtual_ap && (ref $existing_virtual_ap->{collection}->[0]->{uplink} eq "HASH") && ($existing_virtual_ap->{collection}->[0]->{uplink}->{link}->{name} ne $opt->{sector_name})) {
+ $update_sector = 1;
+ }
+
+ # Attach newly created virtual ap to tower sector ap or if sector has changed.
+ $self->api_modify_accesspoint($virtual_name, $opt->{sector_name}) unless ($self->{'__saisei_error'} || ($existing_virtual_ap && !$update_sector));
+
+ # set access point to existing one or newly created one.
+ my $accesspoint = $existing_virtual_ap ? $existing_virtual_ap : $self->api_get_accesspoint($virtual_name);
+
+ return $accesspoint;
+}
+
sub export_provisioned_services {
my $job = shift;
my $param = shift;
my $svc_count = scalar @svcs;
my %status = {};
- for (my $c=10; $c <=100; $c=$c+10) { $status{int($svc_count * ($c/100))} = $c; }
+ for (my $c=1; $c <=100; $c=$c+1) { $status{int($svc_count * ($c/100))} = $c; }
my $process_count=0;
foreach my $svc (@svcs) {
if ($status{$process_count}) { my $s = $status{$process_count}; $job->update_statustext($s); }
## check if service exists as host if not export it.
- _export_insert($part_export,$svc) unless api_get_host($part_export, $svc->{Hash}->{ip_addr});
+ my $host = api_get_host($part_export, $svc->{Hash}->{ip_addr});
+ die $host->{message} if $host->{message};
+ warn "Exporting service ".$svc->{Hash}->{ip_addr}."\n" if ($part_export->option('debug'));
+ my $export_error = _export_insert($part_export,$svc) unless $host->{collection};
+ die $export_error if $export_error;
$process_count++;
}