use REST::Client;
use Data::Dumper;
use FS::Conf;
+use Carp qw(carp);
=pod
<OL>
<LI>
Create a new service definition and set the table to svc_broadband. The service name will become the Saisei rate plan name.
-Set the upload and download speed for the service. This is required to be able to export the service to Saisei.
+Set the upload speed, download speed, and tower to be required for the service. This is required to be able to export the service to Saisei.
Attach this Saisei export to this service.
</LI>
<P>
</LI>
<P>
<LI>
-Provision the service, making sure to enter the IP address associated with this service and select the tower and sector for it's access point.
+Provision the service, making sure to enter the IP address associated with this service, the upload and download speed are correct, and select the tower and sector for it's access point.
This provisioned service will then be exported as a host to Saisei.
<P>
Unprovisioning this service will set the host entry at Saisei to the default rate plan with the user and access point set to <i>none</i>.
</LI>
</OL>
<P>
-
+<A HREF="http://www.freeside.biz/mediawiki/index.php/Saisei_provisioning_export" target="_new">Documentation</a>
END
);
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) = @_;
- $self->_export_insert($svc_broadband);
- return '';
+ my $error = $self->_export_insert($svc_broadband);
+ return $error;
}
sub _export_delete {
sub export_partsvc {
my ($self, $svc_part) = @_;
+ if ( $FS::svc_Common::noexport_hack ) {
+ carp 'export_partsvc() suppressed by noexport_hack'
+ if $self->option('debug');
+ return;
+ }
+
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 )) {
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 = {
'sector_downrate_limit' => $tower_sector->{Hash}->{down_rate_limit},
'modify_existing' => '1', # modify an existing access point with this info
};
- my $sector_access_point = process_sector($self, $sector_opt);
+ my $sector_access_point = process_sector($self, $sector_opt) unless ($sector_name eq "_default");
+ return $sector_access_point if $sector_access_point->{error};
}
- return $self->api_error;
+ return { error => $self->api_error, };
}
## creates the rateplan 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;
+ $rateplan_name =~ s/\s/_/g; $rateplan_name =~ s/[^A-Za-z0-9\-_]//g;
return $rateplan_name;
}
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');
+ warn "Saisei Response Code is ".$client->responseCode()."\n" if $self->option('debug');
my $result;
if ($client->responseCode() eq '200' || $client->responseCode() eq '201') {
eval { $result = decode_json($client->responseContent()) };
unless ($result) {
- $self->{'__saisei_error'} = "Error decoding json: $@";
+ $self->{'__saisei_error'} = "Error decoding json from Saisei";
+ warn "Saisei RC 201 Response Content is not json\n".$client->responseContent()."\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 from Saisei";
+ warn "Saisei RC 404 Response Content is not json\n".$client->responseContent()."\n" if $self->option('debug');
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 "Saisei 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 "Saisei 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");
- warn "Response Content is\n".$client->responseContent."\n" if $self->option('debug');
+ $self->{'__saisei_error'} = "Bad response from server during $method , received responce code: " . $client->responseCode() . " and message: " . $client->responseContent();
+ warn "Saisei 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 { message => $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);
+ return { error => $self->api_error, } if $self->api_error;
return $accesspoint;
}
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};
# set access point to existing one or newly created one.
my $accesspoint = $existing_sector_ap ? $existing_sector_ap : $self->api_get_accesspoint($sector_name);
+ return { error => $self->api_error, } if $self->api_error;
+ 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;
}
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++;
}