Esempio n. 1
0
File: commands.py Progetto: zoot/cli
 def run(self, context, args, kwargs, opargs):
     # Enclose ipv6 urls in '[]' according to ipv6 url spec
     my_ips = [
         wrap_address(ip)
         for ip in context.call_sync('network.config.get_my_ips',
                                     timeout=60)
     ]
     my_protocols = context.call_sync('system.ui.get_config', timeout=60)
     urls = []
     for proto in my_protocols['webui_protocol']:
         proto_port = my_protocols['webui_{0}_port'.format(proto.lower())]
         if proto_port is not None:
             if proto_port in [80, 443]:
                 for x in my_ips:
                     urls.append(
                         {'url': '{0}://{1}'.format(proto.lower(), x)})
             else:
                 for x in my_ips:
                     urls.append({
                         'url':
                         '{0}://{1}:{2}'.format(proto.lower(), x,
                                                proto_port)
                     })
     return Sequence(
         _("You may try the following URLs to access the web user interface:"
           ), Table(urls, [Table.Column(_('URLs (url)'), 'url')]))
Esempio n. 2
0
    def connect(self, url, parent, **kwargs):
        """ Open a connection.

        Args:
            url (ParseResult): The url to open.
            parent (Connection): The connection wrapper class object.

        Kwargs:
            username (str): The username to login with.
            hostname (str): The hostname to connect to.
            port (int): The port to connect to.

        Raises:
            RuntimeError, ValueError
        """
        self.scheme_default_port = 80
        self.parent = parent
        self.username = url.username
        self.port = url.port

        if url.hostname:
            self.hostname = url.hostname
        elif url.netloc:
            self.hostname = url.netloc
            if '@' in self.hostname:
                temp, self.hostname = self.hostname.split('@')
        elif url.path:
            self.hostname = url.path

        if not self.parent:
            raise RuntimeError('ClientTransportWS can be only created inside of a class')

        if not self.username:
                self.username = kwargs.get('username', None)
        else:
            if 'username' in kwargs:
                raise ValueError('Username cannot be delared in both url and arguments.')
        if self.username:
            raise ValueError('Username cannot be delared at this state for ws transport type.')

        if not self.hostname:
            self.hostname = kwargs.get('hostname', "127.0.0.1")
        else:
            if 'hostname' in kwargs:
                raise ValueError('Host name cannot be delared in both url and arguments.')

        if not self.port:
            self.port = kwargs.get('port', self.scheme_default_port)
        else:
            if 'port' in kwargs:
                raise ValueError('Port cannot be delared in both url and arguments.')

        ws_url = 'ws://{0}:{1}/dispatcher/socket'.format(wrap_address(self.hostname), self.port)
        self.ws = self.WebSocketHandler(ws_url, self)
        self.ws.connect()
        self.opened.wait()
Esempio n. 3
0
 def run(self, context, args, kwargs, opargs):
     # Enclose ipv6 urls in '[]' according to ipv6 url spec
     my_ips = [wrap_address(ip) for ip in context.call_sync('network.config.get_my_ips', timeout=60)]
     my_protocols = context.call_sync('system.ui.get_config', timeout=60)
     urls = []
     for proto in my_protocols['webui_protocol']:
         proto_port = my_protocols['webui_{0}_port'.format(proto.lower())]
         if proto_port is not None:
             if proto_port in [80, 443]:
                 for x in my_ips:
                     urls.append({'url': '{0}://{1}'.format(proto.lower(), x)})
             else:
                 for x in my_ips:
                     urls.append({'url': '{0}://{1}:{2}'.format(proto.lower(), x, proto_port)})
     return Table(urls, [Table.Column(_('Web interface URLs'), 'url')])
Esempio n. 4
0
def get_freenas_peer_client(parent, remote):
    try:
        address = socket.gethostbyname(remote)
    except socket.error as err:
        raise TaskException(err.errno, '{0} is unreachable'.format(remote))

    host = parent.dispatcher.call_sync(
        'peer.query', [
            ('or', [
                ('credentials.address', '=', remote),
                ('credentials.address', '=', address),
            ]),
            ('type', '=', 'freenas')
        ],
        {'single': True}
    )
    if not host:
        raise TaskException(errno.ENOENT, 'There are no known keys to connect to {0}'.format(remote))

    with io.StringIO() as f:
        f.write(parent.configstore.get('peer.freenas.key.private'))
        f.seek(0)
        pkey = RSAKey.from_private_key(f)

    credentials = host['credentials']

    try:
        client = Client()
        with tempfile.NamedTemporaryFile('w') as host_key_file:
            host_key_file.write(remote + ' ' + credentials['hostkey'])
            host_key_file.flush()
            client.connect(
                'ws+ssh://freenas@{0}'.format(wrap_address(remote)),
                port=credentials['port'],
                host_key_file=host_key_file.name,
                pkey=pkey
            )
        client.login_service('replicator')
        return client

    except (AuthenticationException, SSHException):
        raise TaskException(errno.EAUTH, 'Cannot connect to {0}'.format(remote))
    except OSError as err:
        raise TaskException(errno.ECONNREFUSED, 'Cannot connect to {0}: {1}'.format(remote, err))
Esempio n. 5
0
def get_freenas_peer_client(parent, remote):
    try:
        address = socket.gethostbyname(remote)
    except socket.error as err:
        raise TaskException(err.errno, '{0} is unreachable'.format(remote))

    host = parent.dispatcher.call_sync(
        'peer.query', [
            ('or', [
                ('credentials.address', '=', remote),
                ('credentials.address', '=', address),
            ]),
            ('type', '=', 'freenas')
        ],
        {'single': True}
    )
    if not host:
        raise TaskException(errno.ENOENT, 'There are no known keys to connect to {0}'.format(remote))

    with io.StringIO() as f:
        f.write(parent.configstore.get('peer.freenas.key.private'))
        f.seek(0)
        pkey = RSAKey.from_private_key(f)

    credentials = host['credentials']

    try:
        client = Client()
        with tempfile.NamedTemporaryFile('w') as host_key_file:
            host_key_file.write(remote + ' ' + credentials['hostkey'])
            host_key_file.flush()
            client.connect(
                'ws+ssh://freenas@{0}'.format(wrap_address(remote)),
                port=credentials['port'],
                host_key_file=host_key_file.name,
                pkey=pkey
            )
        client.login_service('replicator')
        return client

    except (AuthenticationException, SSHException):
        raise TaskException(errno.EAUTH, 'Cannot connect to {0}'.format(remote))
    except OSError as err:
        raise TaskException(errno.ECONNREFUSED, 'Cannot connect to {0}: {1}'.format(remote, err))
Esempio n. 6
0
    def run(self, peer, initial_credentials):
        hostid = self.dispatcher.call_sync('system.info.host_uuid')
        hostname = self.dispatcher.call_sync(
            'system.general.get_config')['hostname']
        remote_peer_name = hostname
        credentials = peer['credentials']
        remote = credentials.get('address')
        port = credentials.get('port', 22)
        username = initial_credentials.get('username')
        password = initial_credentials.get('password')
        auth_code = initial_credentials.get('auth_code')
        key_auth = initial_credentials.get('key_auth')

        local_ssh_config = self.dispatcher.call_sync('service.sshd.get_config')

        if self.datastore.exists('peers', ('credentials.address', '=', remote),
                                 ('type', '=', 'freenas')):
            raise TaskException(
                errno.EEXIST,
                'FreeNAS peer entry for {0} already exists'.format(remote))

        remote_client = Client()

        try:
            if auth_code:
                try:
                    remote_client.connect('ws://{0}'.format(
                        wrap_address(remote)))
                except (AuthenticationException, OSError,
                        ConnectionRefusedError):
                    raise TaskException(
                        errno.ECONNABORTED,
                        'Cannot connect to {0}:{1}'.format(remote, port))

                try:
                    remote_host_uuid, pubkey = remote_client.call_sync(
                        'peer.freenas.auth_with_code', auth_code, hostname,
                        local_ssh_config['port'])
                except RpcException as err:
                    raise TaskException(err.code, err.message)

                try:
                    self.dispatcher.call_sync('peer.freenas.put_temp_pubkey',
                                              pubkey)
                    if not self.dispatcher.test_or_wait_for_event(
                            'peer.changed',
                            lambda ar: ar['operation'] == 'create' and
                            remote_host_uuid in ar['ids'],
                            lambda: self.datastore.exists(
                                'peers', ('id', '=', remote_host_uuid)),
                            timeout=30):
                        raise TaskException(
                            errno.EAUTH,
                            'FreeNAS peer creation failed. Check connection to host {0}.'
                            .format(remote))
                finally:
                    self.dispatcher.call_sync(
                        'peer.freenas.remove_temp_pubkey', pubkey)

            else:
                try:
                    if key_auth:
                        with io.StringIO() as f:
                            f.write(
                                self.configstore.get(
                                    'peer.freenas.key.private'))
                            f.seek(0)
                            pkey = RSAKey.from_private_key(f)

                        max_tries = 50
                        while True:
                            try:
                                remote_client.connect(
                                    'ws+ssh://freenas@{0}'.format(
                                        wrap_address(remote)),
                                    pkey=pkey,
                                    port=port)
                                break
                            except AuthenticationException:
                                if max_tries:
                                    max_tries -= 1
                                    time.sleep(1)
                                else:
                                    raise
                    else:
                        remote_client.connect('ws+ssh://{0}@{1}'.format(
                            username, wrap_address(remote)),
                                              port=port,
                                              password=password)

                    remote_client.login_service('replicator')
                except (AuthenticationException, OSError,
                        ConnectionRefusedError):
                    raise TaskException(
                        errno.ECONNABORTED,
                        'Cannot connect to {0}:{1}'.format(remote, port))

                local_host_key, local_pub_key = self.dispatcher.call_sync(
                    'peer.freenas.get_ssh_keys')
                remote_host_key, remote_pub_key = remote_client.call_sync(
                    'peer.freenas.get_ssh_keys')
                ip_at_remote_side = remote_client.local_address[0]

                remote_hostname = remote_client.call_sync(
                    'system.general.get_config')['hostname']

                remote_host_key = remote_host_key.rsplit(' ', 1)[0]
                local_host_key = local_host_key.rsplit(' ', 1)[0]

                if remote_client.call_sync('peer.query',
                                           [('id', '=', hostid)]):
                    raise TaskException(
                        errno.EEXIST,
                        'Peer entry of {0} already exists at {1}'.format(
                            hostname, remote))

                peer['credentials'] = {
                    '%type': 'freenas-credentials',
                    'pubkey': remote_pub_key,
                    'hostkey': remote_host_key,
                    'port': port,
                    'address': remote_hostname
                }

                local_id = remote_client.call_sync('system.info.host_uuid')
                peer['id'] = local_id
                peer['name'] = remote_hostname
                ip = socket.gethostbyname(remote)

                created_ids = self.join_subtasks(
                    self.run_subtask('peer.freenas.create_local', peer, ip,
                                     True))

                peer['id'] = hostid
                peer['name'] = remote_peer_name
                peer['credentials'] = {
                    '%type': 'freenas-credentials',
                    'pubkey': local_pub_key,
                    'hostkey': local_host_key,
                    'port': local_ssh_config['port'],
                    'address': hostname
                }

                try:
                    call_task_and_check_state(remote_client,
                                              'peer.freenas.create_local',
                                              peer, ip_at_remote_side)
                except TaskException:
                    self.datastore.delete('peers', local_id)
                    self.dispatcher.dispatch_event('peer.changed', {
                        'operation': 'delete',
                        'ids': [local_id]
                    })
                    raise

                return created_ids[0]
        finally:
            remote_client.disconnect()
Esempio n. 7
0
    def run(self, peer, initial_credentials):
        hostid = self.dispatcher.call_sync('system.info.host_uuid')
        hostname = self.dispatcher.call_sync('system.general.get_config')['hostname']
        remote_peer_name = hostname
        credentials = peer['credentials']
        remote = credentials.get('address')
        port = credentials.get('port', 22)
        username = initial_credentials.get('username')
        password = initial_credentials.get('password')
        auth_code = initial_credentials.get('auth_code')
        key_auth = initial_credentials.get('key_auth')

        local_ssh_config = self.dispatcher.call_sync('service.sshd.get_config')

        if self.datastore.exists('peers', ('credentials.address', '=', remote), ('type', '=', 'freenas')):
            raise TaskException(
                errno.EEXIST,
                'FreeNAS peer entry for {0} already exists'.format(remote)
            )

        remote_client = Client()

        try:
            if auth_code:
                try:
                    remote_client.connect('ws://{0}'.format(wrap_address(remote)))
                except (AuthenticationException, OSError, ConnectionRefusedError):
                    raise TaskException(errno.ECONNABORTED, 'Cannot connect to {0}:{1}'.format(remote, port))

                try:
                    remote_host_uuid, pubkey = remote_client.call_sync(
                        'peer.freenas.auth_with_code',
                        auth_code,
                        hostname,
                        local_ssh_config['port']
                    )
                except RpcException as err:
                    raise TaskException(err.code, err.message)

                try:
                    self.dispatcher.call_sync('peer.freenas.put_temp_pubkey', pubkey)
                    if not self.dispatcher.test_or_wait_for_event(
                        'peer.changed',
                        lambda ar: ar['operation'] == 'create' and remote_host_uuid in ar['ids'],
                        lambda: self.datastore.exists('peers', ('id', '=', remote_host_uuid)),
                        timeout=30
                    ):
                        raise TaskException(
                            errno.EAUTH,
                            'FreeNAS peer creation failed. Check connection to host {0}.'.format(remote)
                        )
                finally:
                    self.dispatcher.call_sync('peer.freenas.remove_temp_pubkey', pubkey)

            else:
                try:
                    if key_auth:
                        with io.StringIO() as f:
                            f.write(self.configstore.get('peer.freenas.key.private'))
                            f.seek(0)
                            pkey = RSAKey.from_private_key(f)

                        max_tries = 50
                        while True:
                            try:
                                remote_client.connect('ws+ssh://freenas@{0}'.format(
                                    wrap_address(remote)), pkey=pkey, port=port
                                )
                                break
                            except AuthenticationException:
                                if max_tries:
                                    max_tries -= 1
                                    time.sleep(1)
                                else:
                                    raise
                    else:
                        remote_client.connect(
                            'ws+ssh://{0}@{1}'.format(username, wrap_address(remote)),
                            port=port,
                            password=password
                        )

                    remote_client.login_service('replicator')
                except (AuthenticationException, OSError, ConnectionRefusedError):
                    raise TaskException(errno.ECONNABORTED, 'Cannot connect to {0}:{1}'.format(remote, port))

                local_host_key, local_pub_key = self.dispatcher.call_sync('peer.freenas.get_ssh_keys')
                remote_host_key, remote_pub_key = remote_client.call_sync('peer.freenas.get_ssh_keys')
                ip_at_remote_side = remote_client.local_address[0]

                remote_hostname = remote_client.call_sync('system.general.get_config')['hostname']

                remote_host_key = remote_host_key.rsplit(' ', 1)[0]
                local_host_key = local_host_key.rsplit(' ', 1)[0]

                if remote_client.call_sync('peer.query', [('id', '=', hostid)]):
                    raise TaskException(errno.EEXIST, 'Peer entry of {0} already exists at {1}'.format(hostname, remote))

                peer['credentials'] = {
                    '%type': 'freenas-credentials',
                    'pubkey': remote_pub_key,
                    'hostkey': remote_host_key,
                    'port': port,
                    'address': remote_hostname
                }

                local_id = remote_client.call_sync('system.info.host_uuid')
                peer['id'] = local_id
                peer['name'] = remote_hostname
                ip = socket.gethostbyname(remote)

                created_id = self.run_subtask_sync(
                    'peer.freenas.create_local',
                    peer,
                    ip,
                    True
                )

                peer['id'] = hostid
                peer['name'] = remote_peer_name
                peer['credentials'] = {
                    '%type': 'freenas-credentials',
                    'pubkey': local_pub_key,
                    'hostkey': local_host_key,
                    'port': local_ssh_config['port'],
                    'address': hostname
                }

                try:
                    call_task_and_check_state(
                        remote_client,
                        'peer.freenas.create_local',
                        peer,
                        ip_at_remote_side
                    )
                except TaskException:
                    self.datastore.delete('peers', local_id)
                    self.dispatcher.dispatch_event('peer.changed', {
                        'operation': 'delete',
                        'ids': [local_id]
                    })
                    raise

                return created_id
        finally:
            remote_client.disconnect()
Esempio n. 8
0
    def connect(self, url, parent, **kwargs):
        """ Open a connection.

        Args:
            url (ParseResult): The url to open.
            parent (Connection): The connection wrapper class object.

        Kwargs:
            username (str): The username to login with.
            hostname (str): The hostname to connect to.
            port (int): The port to connect to.

        Raises:
            RuntimeError, ValueError
        """
        self.scheme_default_port = 80
        self.parent = parent
        self.username = url.username
        self.port = url.port

        if url.hostname:
            self.hostname = url.hostname
        elif url.netloc:
            self.hostname = url.netloc
            if '@' in self.hostname:
                temp, self.hostname = self.hostname.split('@')
        elif url.path:
            self.hostname = url.path

        if not self.parent:
            raise RuntimeError(
                'ClientTransportWS can be only created inside of a class')

        if not self.username:
            self.username = kwargs.get('username', None)
        else:
            if 'username' in kwargs:
                raise ValueError(
                    'Username cannot be delared in both url and arguments.')
        if self.username:
            raise ValueError(
                'Username cannot be delared at this state for ws transport type.'
            )

        if not self.hostname:
            self.hostname = kwargs.get('hostname', "127.0.0.1")
        else:
            if 'hostname' in kwargs:
                raise ValueError(
                    'Host name cannot be delared in both url and arguments.')

        if not self.port:
            self.port = kwargs.get('port', self.scheme_default_port)
        else:
            if 'port' in kwargs:
                raise ValueError(
                    'Port cannot be delared in both url and arguments.')

        ws_url = 'ws://{0}:{1}/dispatcher/socket'.format(
            wrap_address(self.hostname), self.port)
        self.ws = self.WebSocketHandler(ws_url, self)
        self.ws.connect()
        self.opened.wait()