Fichier rclone.conf impossible à créer depuis le plugin

Salut @thanaus

Je viens finalement de passé le cap : remplacer mon cron par ton plugin… (j’ai plus de souci sur la limitation de la BP). J’en profite de faire un petit retour :

  • A l’installation du plugin (la dernière beta), il manque le répertoire …/cloudsyncpro/core/config/
  • Conséquence directe, mais pas unique que je pense : impossible de créer le fichier rclone.conf pour Gdrive du moins

Comme j’ai mon fichier conf du service, qui fonctionne =>création du répertoire, copie, droits, remplacement de la section par l’id de l’équipement… ça roule du premier coup :sweat_smile:

Pour voir je teste une autre équipement, même token …

[2020-08-13 11:18:29][ALERT] : Starting task (Gdrive 2/Syn2 #9042)
[2020-08-13 11:18:29][DEBUG] : execute:: pid:'4289' rclone:'/var/www/html/plugins/cloudsyncpro/3rparty/rclone-v1.41-linux-arm64/rclone -v --log-file /var/www/html/core/class/../../log/cloudsyncpro.#9042 --config /var/www/html/plugins/cloudsyncpro/core/config/rclone.conf sync \'/jeedom/backup\' 833:\'jeedom/backup2\''
[2020-08-13 11:18:39][DEBUG] : execute:: statistics:array (   'Errors' => NULL,   'Checks' => NULL,   'Transferred' => NULL,   'Elapsed time' => NULL,   'Bytes Loaded (Speed)' => NULL, )
[2020-08-13 11:18:39][ERROR] : Erreur exécution de la commande [Aucun][Gdrive 2][Syn2] : Task finished on Error (Gdrive 2/Syn2 #9042)
2020/08/13 11:18:29 ERROR : Couldn't find home directory or read HOME or XDG_CONFIG_HOME environment variables.
2020/08/13 11:18:29 ERROR : Defaulting to storing config in current directory.
2020/08/13 11:18:29 ERROR : Use --config flag to workaround.
2020/08/13 11:18:29 ERROR : Error was: user: Current not implemented on linux/arm64
2020/08/13 11:18:29 Failed to create file system for "833:jeedom/backup2": didn't find section in config file

Et effectivement le fichier rclone ne contient pas de nouvelles infos… L’id précédent est bien là mais pas de 833…

Bon courage

Bonjour @naboleo

Je viens de faire un test avec la dernière version beta sur une installation from scratch et je ne reproduis pas ce problème.
Le répertoire « …/cloudsyncpro/core/config » n’existe pas à l’installation mais créé automatiquement lors de la sauvegarde d’un équipement. Cette correction a été mise en place en Janvier 2020.

Peux-tu m’indiquer exactement la version du plugin ainsi que le contenu du fichier « …/cloudsyncpro/core/class/cloudsyncpro.class.php » ?

Salut…

Version installée : beta du 2020-04-04 03:13:14

Quant au fichier

<?php

/* This file is part of Jeedom.
 *
 * Jeedom is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Jeedom is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Jeedom. If not, see <http://www.gnu.org/licenses/>.
 */

/* * ***************************Includes********************************* */
require_once __DIR__  . '/../../../../core/php/core.inc.php';

define('__CLOUDSYNCPRO__', dirname(dirname(dirname(__FILE__))));
require_once (__CLOUDSYNCPRO__.'/3rparty/Rclone-API-PHP/src/Rclone/autoload.php');
define('__RCLONE_VERSION__', '1.41');

class cloudsyncpro extends eqLogic {
    /*     * *************************Attributs****************************** */



    /*     * ***********************Methode static*************************** */

    /*
     * Fonction exécutée automatiquement toutes les minutes par Jeedom
      public static function cron() {

      }
     */


    /*
     * Fonction exécutée automatiquement toutes les heures par Jeedom
      public static function cronHourly() {

      }
     */

    /*
     * Fonction exécutée automatiquement tous les jours par Jeedom
      public static function cronDaily() {

      }
     */

      public static function dependancy_info() {
        log::add('cloudsyncpro', 'debug', 'dependancy_info::');

        $return = array();
        $return['progress_file'] = jeedom::getTmpFolder('cloudsyncpro') . '/dependency';
        $return['state'] = 'nok';

        $array = array(
            'Linux' => array(
                'armv6l' => 'linux-arm',
                'armv7l' => 'linux-arm',
	        'x86_64' => 'linux-amd64',
                'aarch64' => 'linux-arm64',
                'i686'   => 'linux-386',
             ),
        );

        $uname = posix_uname();
        $version = config::byKey('rclone_version', 'cloudsyncpro');
        log::add('cloudsyncpro', 'debug', 'dependancy_info:: posix_uname:' . var_export($uname, true));
        log::add('cloudsyncpro', 'debug', 'dependancy_info:: version:' . var_export($version, true));

        $binary = __CLOUDSYNCPRO__ . '/3rparty/' . 'rclone-v' . $version . '-' . $array[$uname['sysname']][$uname['machine']] . '/rclone';
        if (file_exists($binary)) {
            $config = array('binary' => $binary,
                            'loglevel' => log::getLogLevel('cloudsyncpro'),
                            'logfile' => tempnam(jeedom::getTmpFolder('cloudsyncpro'), "_"));
            $client = new Rclone\Clients\RCApiClient($config);

            list($pid, $rclone) = $client->version();

            log::add('cloudsyncpro', 'debug', 'dependancy_info:: pid:' . var_export($pid, true) . ' rclone:' . var_export($rclone, true));

            $result = $version = NULL;
            while ($result == NULL || count(preg_split("/\n/", $result)) > 2) {
                $result = shell_exec(sprintf("ps %d", $pid));
                sleep(1);
            }

            $result = file($config['logfile']);
            foreach ($result as $value) {
                if (preg_match('/rclone v(.+)/', $value, $matches)) {
                    $version = $matches[1];
                    break;
                }
            }
            unlink($config['logfile']);

            log::add('cloudsyncpro', 'debug', 'dependancy_info:: VERSION:' . var_export($version, true));

            if ( isset($version) && $version == __RCLONE_VERSION__ ) {
                config::save('rclone_binary', $binary, 'cloudsyncpro');
                $return['state'] = 'ok';
            }
        }
        
        return $return;
      }

      public static function dependancy_install() {
        log::add('cloudsyncpro', 'debug', 'dependancy_install::');

        log::remove(__CLASS__ . '_update');
        config::save('rclone_version', __RCLONE_VERSION__, 'cloudsyncpro');
        config::remove('rclone_binary','cloudsyncpro');
        return array('script' => __CLOUDSYNCPRO__ . '/resources/install_#stype#.sh ' . jeedom::getTmpFolder('cloudsyncpro') . '/dependency', 'log' => log::getPathToLog(__CLASS__ . '_update'));
      }


    /*     * *********************Méthodes d'instance************************* */

    public function preInsert() {
        
    }

    public function postInsert() {
        
    }

    public function preSave() {
        
    }

    public function postSave() {
        log::add('cloudsyncpro', 'debug', 'postSave:: this:' . var_export($this, true));

        $array = $this->loadConfigFile();
        $isSave = false;

        $cryptKey = array(0x9c, 0x93, 0x5b, 0x48, 0x73, 0x0a, 0x55, 0x4d, 0x6b, 0xfd, 0x7c, 0x63, 0xc8, 0x86, 0xa9, 0x2b, 0xd3, 0x90, 0x19, 0x8e, 0xb8, 0x12, 0x8a, 0xfb, 0xf4, 0xde, 0x16, 0x2b, 0x8b, 0x95, 0xf6, 0x38);

        switch ($this->getConfiguration('type')) {
            case 'drive':
                require_once (__CLOUDSYNCPRO__.'/3rparty/google-api-php-client-2.2.1/vendor/autoload.php');

                if ($this->getConfiguration('param1') && $this->getConfiguration('param2') == 1) {
		    $client = new Google_Client();
                    $client->setClientId('202264815644.apps.googleusercontent.com');
                    $client->setClientSecret('X4Z3ca8xfWDb1Voo-F9a7ZxJ');
                    $client->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');

                    $token = $client->fetchAccessTokenWithAuthCode($this->getConfiguration('param1'));
                    if (isset($token['error_description'])) {
                        throw new Exception('Erreur de configuration : ' . $token['error_description']);
                    }

                    $array[$this->getId()] = array(
			'type' => 'drive',
			'client_id' => '',
			'client_secret' => '',
			'scope' => 'drive',
			'root_folder_id' => '',
			'service_account_file' => '',
			'token' => '{"access_token":"' . $token['access_token'] . '","token_type":"Bearer","refresh_token":"' . $token['refresh_token'] . '","expiry":"' . date('Y-m-d\TG:i:s.uP', $token['created'] + $token['expires_in']) . '"}',
                    );

                    $this->setConfiguration('param2', 0);
                    $this->save();

                    $isSave = true;
                }
                break;
            case 'dropbox':
                if ($this->getConfiguration('param1')) {
                    $array[$this->getId()] = array(
			'type' => 'dropbox',
			'app_key' => '',
			'app_secret' => '',
			'token' => '{"access_token":"' . $this->getConfiguration('param1') . '","token_type":"bearer","expiry":"0001-01-01T00:00:00Z"}',
                    );
                    $isSave = true;
                }
                break;
            case 'ftp':
                if ($this->getConfiguration('param1') && $this->getConfiguration('param2') && $this->getConfiguration('param3') && $this->getConfiguration('param4')) {
                    $iv = openssl_random_pseudo_bytes(16);
                    $cipher = openssl_encrypt($this->getConfiguration('param4'), "AES-256-CTR", call_user_func_array('pack', array_merge(array('C*'), $cryptKey)), OPENSSL_RAW_DATA, $iv);

                    $array[$this->getId()] = array(
			'type' => 'ftp',
			'host' => $this->getConfiguration('param1'),
			'user' => $this->getConfiguration('param3'),
			'port' => $this->getConfiguration('param2'),
                        'pass' => rtrim(str_replace(array('+', '/'), array('-', '_'), base64_encode($iv . $cipher)), '='),
                    );
                    $isSave = true;
                }
                break;
            case 'sftp':
                if ($this->getConfiguration('param1') && $this->getConfiguration('param2') && $this->getConfiguration('param3') && $this->getConfiguration('param4')) {
                    $iv = openssl_random_pseudo_bytes(16);
                    $cipher = openssl_encrypt($this->getConfiguration('param4'), "AES-256-CTR", call_user_func_array('pack', array_merge(array('C*'), $cryptKey)), OPENSSL_RAW_DATA, $iv);

                    $array[$this->getId()] = array(
			'type' => 'sftp',
			'host' => $this->getConfiguration('param1'),
			'user' => $this->getConfiguration('param3'),
			'port' => $this->getConfiguration('param2'),
                        'pass' => rtrim(str_replace(array('+', '/'), array('-', '_'), base64_encode($iv . $cipher)), '='),
			'keyfile' => '',
                    );
                    $isSave = true;
                }
                break;
            case 'nextcloud':
                if ($this->getConfiguration('param1') && $this->getConfiguration('param2') && $this->getConfiguration('param3')) {
                    $iv = openssl_random_pseudo_bytes(16);
                    $cipher = openssl_encrypt($this->getConfiguration('param3'), "AES-256-CTR", call_user_func_array('pack', array_merge(array('C*'), $cryptKey)), OPENSSL_RAW_DATA, $iv);

                    $array[$this->getId()] = array(
			'type' => 'webdav',
			'url' => $this->getConfiguration('param1'),
			'vendor' => 'nextcloud',
			'user' => $this->getConfiguration('param2'),
                        'pass' => rtrim(str_replace(array('+', '/'), array('-', '_'), base64_encode($iv . $cipher)), '='),
                    );
                    $isSave = true;
                }
                break;
            case 'local':
                break;
        }

        if ( $isSave === true ) {
            $this->saveConfigFile($array);
        }
    }

    public function preUpdate() {
        
    }

    public function postUpdate() {
        
    }

    public function preRemove() {
        log::add('cloudsyncpro', 'debug', 'preRemove:: this:' . var_export($this, true));

        $array = $this->loadConfigFile();

        if (array_key_exists($this->getId(), $array)) {
            unset($array[$this->getId()]);
            $this->saveConfigFile($array);
        }
    }

    public function postRemove() {
        
    }

    private function loadConfigFile() {
        log::add('cloudsyncpro', 'debug', 'loadConfigFile::');

        $rclone_conf = __CLOUDSYNCPRO__ . '/core/config/rclone.conf';
        $array = array();

        if (file_exists($rclone_conf)) {
            $array = parse_ini_file($rclone_conf, true, INI_SCANNER_RAW);
        }
        log::add('cloudsyncpro', 'debug', 'loadConfigFile:: rclone.conf:' . var_export($array, true));

        return $array;
    }

    private function saveConfigFile($array = array()) {
        log::add('cloudsyncpro', 'debug', 'saveConfigFile:: array:' . var_export($array, true));

        $rclone_conf = __CLOUDSYNCPRO__ . '/core/config/rclone.conf';

        $content = '';
        foreach ($array as $key=>$elem) {
            $content .= '[' . $key . ']' . PHP_EOL; 
            foreach ($elem as $key2=>$elem2) { 
                if ($elem2 == '') {
                    $content .= $key2 . ' = ' . PHP_EOL; 
                }
                else {
                    $content .= $key2 . ' = ' . $elem2 . PHP_EOL;
                }
            }
	    $content .= PHP_EOL;
        }

        log::add('cloudsyncpro', 'debug', 'saveConfigFile:: content:' . var_export($content, true));

        if (!is_dir(dirname($rclone_conf))) mkdir(dirname($rclone_conf));
        if (false === file_put_contents($rclone_conf, $content)) {
            throw new \Exception('Unable to write configuration file \'' . $rclone_conf . '\'');
        }
    }

    /*
     * Non obligatoire mais permet de modifier l'affichage du widget si vous en avez besoin
      public function toHtml($_version = 'dashboard') {

      }
     */

    /*
     * Non obligatoire mais ca permet de déclencher une action après modification de variable de configuration
    public static function postConfig_<Variable>() {
    }
     */

    /*
     * Non obligatoire mais ca permet de déclencher une action avant modification de variable de configuration
    public static function preConfig_<Variable>() {
    }
     */

    /*     * **********************Getteur Setteur*************************** */
}

class cloudsyncproCmd extends cmd {
    /*     * *************************Attributs****************************** */


    /*     * ***********************Methode static*************************** */


    /*     * *********************Methode d'instance************************* */

    /*
     * Non obligatoire permet de demander de ne pas supprimer les commandes même si elles ne sont pas dans la nouvelle configuration de l'équipement envoyé en JS
      public function dontRemoveCmd() {
      return true;
      }
     */

    public function execute($_options = array()) {
        log::add('cloudsyncpro', 'debug', 'execute:: options:' . var_export($_options, true));
        log::add('cloudsyncpro', 'debug', 'execute:: this:' . var_export($this, true));

        log::add('cloudsyncpro', 'debug', 'execute:: this:' . var_export($this->getConfiguration(), true));
        log::add('cloudsyncpro', 'alert', 'Starting task (' . $this->getEqLogic()->getName() . '/' . $this->getName() . ' #' . $this->getId() . ')');

        event::add('jeedom::alert', array(
            'level' => 'warning',
            'page' => 'cloudsyncpro',
            'message' => __('Lancement de la tache (' . $this->getEqLogic()->getName() . '/' . $this->getName() . ' #' . $this->getId() . ')', __FILE__),
        ));

        $config = array('binary' => config::byKey('rclone_binary', 'cloudsyncpro'),
                        'config' => __CLOUDSYNCPRO__ . '/core/config/rclone.conf',
			'loglevel' => log::getLogLevel('cloudsyncpro'),
                        'logfile' => log::getPathToLog('cloudsyncpro.#' . $this->getId()));
        unlink($config['logfile']);
        $client = new Rclone\Clients\RCApiClient($config);

        list($pid, $rclone) = $client->{$this->getConfiguration('command')}($this->getConfiguration(), ($this->getEqLogic()->getConfiguration('type') == 'local' ? NULL : $this->getEqLogic()->getId()));

        log::add('cloudsyncpro', 'debug', 'execute:: pid:' . var_export($pid, true) . ' rclone:' . var_export($rclone, true));

        $statistics = array_fill_keys(array('Errors', 'Checks', 'Transferred', 'Elapsed time', 'Bytes Loaded (Speed)'), NULL);

        $result = NULL;
        while ($result == NULL || count(preg_split("/\n/", $result)) > 2) {
            $result = shell_exec(sprintf("ps %d", $pid));
            sleep(5);
        }

        if ( $this->getConfiguration('command') == 'copy' || $this->getConfiguration('command') == 'sync' ) {
            $result = array_reverse(file($config['logfile']));
            foreach ($result as $value) {
                if (preg_match('/(.+):\s+(.+)/', $value, $matches)) {
                    if (array_key_exists($matches[1], $statistics)) {
                        $statistics[($matches[1] == 'Transferred' && !is_numeric($matches[2])) ? 'Bytes Loaded (Speed)' : $matches[1]] = $matches[2];
                        if (!in_array(NULL, $statistics)) {
                            break;
                        }
                    }
                }
            }
            log::add('cloudsyncpro', 'debug', 'execute:: statistics:' . var_export($statistics, true));

            if ( in_array(NULL, $statistics) ) {
                throw new \Exception('Task finished on Error (' . $this->getEqLogic()->getName() . '/' . $this->getName() . ' #' . $this->getId() . ')');
            }

            foreach ($statistics as $key => $value) {
                $fmtmsg .= $key . ' (' . $value . '), ';
            }
            log::add('cloudsyncpro', 'alert', 'Task finished (' . $this->getEqLogic()->getName() . '/' . $this->getName() . ' #' . $this->getId() . ') : ' . $fmtmsg);
        }
        else {
            log::add('cloudsyncpro', 'alert', 'Task finished (' . $this->getEqLogic()->getName() . '/' . $this->getName() . ' #' . $this->getId() . ')');
        }
    }

    /*     * **********************Getteur Setteur*************************** */
}



au cas ou

root@raspberrypi:/jeedom/perso/pi2mqtt# uname -a
Linux raspberrypi 5.4.51-v8+ #1333 SMP PREEMPT Mon Aug 10 16:58:35 BST 2020 aarch64 GNU/Linux

A ta dispo

Le code de création du répertoire est bien présent…
Il faut bien entendu avoir la coche « Renouvellement » sélectionné avec un token valide pour sauvegarder les données dans le cas du stockage Google Drive.
Est-ce bien ce que tu as fait ?

Dans tous les cas, je ne reproduis pas ce bug et quelque peu embete…
Possible d’avoir un accès à ton installation ?

J’ai fait plusieurs installations, mais en principe oui. J’avais trouvé l’info ici Cloudsync pro et gdrive

PM en cours d’envoi

Ce sujet a été automatiquement fermé après 24 heures suivant le dernier commentaire. Aucune réponse n’est permise dorénavant.