Import provisions and presets

Is there a way to import provisions and presets either separate or bulk? I know I can shove it directly in to the DB (and I’ve done this on previous occasions), but that’s a bit brutal. Like the Download function in the gui, an Upload would be awesome! Very handy to have a baseline setup that can be easily replicated.

To give some context, we are a “solutions provider” for ISP’s in Norway, setting up complete BSS/OSS systems. This is where Genie comes in, and it’s a bit tedious to copy in all our scripts…

:slight_smile:

You can use HTTP GET/PUT to download/upload presets and provisions from the NBI.

I’ve written code to upload/download all the presets/provision scripts/vparams in our environment. I use it to quickly sync dev and prod.

Here is some rough code for you to adapt:

<?php
use GuzzleHttp\Exception\ClientException;

class Scripinator {
    /** @var string */
    private $baseNbiUri;

    /** @var string */
    private $outputDir;

    /** @var bool */
    private $clean;

    /** @var GuzzleHttp\Client */
    private $client;
    
    public function execute(string $direction, string $baseNbiUri, string $outputDir, bool $cleanupFirst = false): void {
        $this->baseNbiUri = $baseNbiUri;
        $this->outputDir = $outputDir;
        $this->clean = $cleanupFirst;
        $this->client = new GuzzleHttp\Client();

        if ($direction === 'download') {
            print(sprintf('Downloading from %s\r\n', $baseNbiUri));

            $this->download('presets', null);
            $this->download('virtual_parameters', 'script');
            $this->download('provisions', 'script');
        }

        if ($direction === 'upload') {
            print(sprintf('Uploading to %s', $baseNbiUri));

            $this->upload('presets');
            $this->upload('virtual_parameters');
            $this->upload('provisions');
        }

        print("Finished!\r\n");
    }

    private function download(string $option, ?string $paramName): void {
        $response = $this->client->get(sprintf('/%s', $option), ['base_uri' => $this->baseNbiUri]);

        $fs = new Filesystem();
        $dir = self::pathCombine($this->outputDir, $option);
        $finder = new Finder();

        if ($this->clean && $fs->exists($dir)) {
            print(sprintf("Cleaning output directory %s\r\n", $dir));

            $files = $finder->files()->in($dir);
            $fs->remove($files->getIterator());
        }

        if (!$fs->exists($dir)) {
            $fs->mkdir($dir);
        }

        if ($response->getStatusCode() === 200) {
            $data = json_decode($response->getBody()->getContents(), true);

            foreach ($data as $item) {
                if ($paramName && array_key_exists($paramName, $item)) {
                    $script = $item[$paramName];
                    $filename = self::pathCombine($dir, sprintf('%s.%s', $item['_id'], 'js'));
                    print(sprintf("Creating file %s\r\n", $filename));
                    file_put_contents($filename, $script);
                } else {
                    $filename = self::pathCombine($dir, sprintf('%s.%s', $item['_id'], 'json'));
                    print(sprintf("Creating file %s\r\n", $filename));
                    file_put_contents($filename, json_encode($item, JSON_PRETTY_PRINT));
                }
            }
        }
    }

    private function upload(string $option): void {
        $dir = self::pathCombine($this->outputDir, $option);
        $finder = new Finder();

        $files = $finder->files()->in($dir);

        /** @var SplFileInfo $file */
        foreach ($files as $file) {
            if ($file->getExtension() === 'json') {
                $data = json_decode($file->getContents(), true);
                $id = $data['_id'];
            } else {
                $data = $file->getContents();
                $id = $file->getBasename('.' . $file->getExtension());
            }

            try {
                print(sprintf("Uploading file %s/%s\r\n", $option, $id));
                $options = [
                    'connection_timeout' => 10,
                    'base_uri'           => $this->baseNbiUri
                ];

                if ($file->getExtension() === 'json') {
                    $options['json'] = $data;
                } else {
                    $options['body'] = $data;
                }

                $result = $this->client->put(sprintf('/%s/%s', $option, $id), $options);

                if ($result->getStatusCode() >= 299) {
                    print(sprintf("Error uploading file %s/%s\r\n", $option, $id));
                }
            } catch (ClientException $ex) {
                print(sprintf("Error uploading file %s/%s\r\n", $option, $id));

                throw $ex;
            }
        }
    }

    private static function pathCombine(...$params): string {
        foreach ($params as &$p) {
            if (mb_strpos($p, DIRECTORY_SEPARATOR) === 0) {
                $p = mb_substr($p, 1);
            }

            if (mb_stripos($p, DIRECTORY_SEPARATOR) === mb_strlen($p)) {
                $p = mb_substr($p, 0, -1);
            }
        }

        return DIRECTORY_SEPARATOR . implode($params, DIRECTORY_SEPARATOR);
    }
}
1 Like

Nice, thanks! I thought about going through the API, but figured I’d ask if there was another way.

There might be more questions coming your way as I’m not a coder, I just hack 'till it works. Not at all a php-dev… :slight_smile:
Trying to make a crude script but I get ‘Uncaught Error: Class ‘GuzzleHttp\Client’ not found in …’
Does php “import” the libraries it needs at “use GuzzleHttp\Exception\ClientException;” ? I read through http://docs.guzzlephp.org/en/stable/overview.html#installation and I think I have it installed as per instructions…

Aaaand I got it running, but now it’s complaining about “Class ‘Filesystem’ not found”… I also see " $finder = new Finder();". Is this a reference to operating system functions? As in, is this run on a mac?

Those come from the Symfony framework. You can replace $fs->exists with file_exists and $fs->mkdir with mkdir

and this block:

if ($this->clean && $fs->exists($dir)) {
    printf("Cleaning output directory %s\r\n", $dir);
    $files = $finder->files()->in($dir);
    $fs->remove($files->getIterator());
}

with this:

if ($this->clean && file_exists($dir)) {
    printf("Cleaning output directory %s\r\n", $dir);
    $files = scandir($dir);
    foreach ($files as $file) {
         unlink($file);
    }
}

Ah, yes. I found the symphony framework and sorta kinda got rid of some errors, but I’ll try to simplify it instead, as you suggest.
:slight_smile:

Oh, and it worked like a charm once I got the right components from Symfony going, Thanks for the hints, further hacking can now commence!