Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataSource sync from git by ssh does not work #12464

Closed
jiuka opened this issue May 4, 2023 · 3 comments · Fixed by #12482
Closed

DataSource sync from git by ssh does not work #12464

jiuka opened this issue May 4, 2023 · 3 comments · Fixed by #12482
Assignees
Labels
status: accepted This issue has been accepted for implementation type: bug A confirmed report of unexpected behavior in the application

Comments

@jiuka
Copy link

jiuka commented May 4, 2023

NetBox version

v3.5.0

Python version

3.10

Steps to Reproduce

  1. Add datasource with ssh git url (ex: ssh://git@bitbucket.host:2222/project/netbox_scripts.git)
  2. Sync the datasource with netbox/manage.py syncdatasource --all --traceback

Expected Behavior

The Datasource is synced.

Observed Behavior

An exception is raised.

porcelain parses the username for ssh from the url. This leads to a error as porcelain tries to call a function while supplying the kwarg username twice.

$ /opt/netbox/netbox/manage.py syncdatasource --all --traceback
[1] Syncing netbox_scripts... Traceback (most recent call last):
  File "/opt/netbox/netbox/core/data_backends.py", line 103, in fetch
    porcelain.clone(
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/porcelain.py", line 505, in clone
    (client, path) = get_transport_and_path(
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 2361, in get_transport_and_path
    return _get_transport_and_path_from_url(
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 2300, in _get_transport_and_path_from_url
    return SSHGitClient.from_parsedurl(parsed, **kwargs), parsed.path
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 1714, in from_parsedurl
    return cls(
TypeError: dulwich.client.SSHGitClient() got multiple values for keyword argument 'username'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/netbox/netbox/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/base.py", line 402, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/base.py", line 448, in execute
    output = self.handle(*args, **options)
  File "/opt/netbox/netbox/core/management/commands/syncdatasource.py", line 36, in handle
    datasource.sync()
  File "/opt/netbox/netbox/core/models/data.py", line 155, in sync
    with backend.fetch() as local_path:
  File "/usr/lib/python3.10/contextlib.py", line 135, in __enter__
    return next(self.gen)
  File "/opt/netbox/netbox/core/data_backends.py", line 108, in fetch
    raise SyncError(f"Fetching remote data failed ({type(e).__name__}): {e} {self.params}")
core.exceptions.SyncError: Fetching remote data failed (TypeError): dulwich.client.SSHGitClient() got multiple values for keyword argument 'username' {'branch': 'main', 'password': '', 'username': 'git'}

It the username parameter is removed from netbox/core/data_backends.py#L104 it still fails as in ssh mode no password is allowed by porcelain.

(venv) netbox-staging@vm-netbox22:~$ /opt/netbox/netbox/manage.py syncdatasource --all --traceback
[1] Syncing netbox_scripts... Traceback (most recent call last):
  File "/opt/netbox/netbox/core/data_backends.py", line 103, in fetch
    porcelain.clone(
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/porcelain.py", line 508, in clone
    return client.clone(
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 705, in clone
    result = self.fetch(path, target, progress=progress, depth=depth)
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 782, in fetch
    result = self.fetch_pack(
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 1098, in fetch_pack
    proto, can_read, stderr = self._connect(b"upload-pack", path)
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 1747, in _connect
    con = self.ssh_vendor.run_command(
  File "/opt/netbox/venv/lib/python3.10/site-packages/dulwich/client.py", line 1571, in run_command
    raise NotImplementedError(
NotImplementedError: Setting password not supported by SubprocessSSHVendor.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/netbox/netbox/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/base.py", line 402, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/core/management/base.py", line 448, in execute
    output = self.handle(*args, **options)
  File "/opt/netbox/netbox/core/management/commands/syncdatasource.py", line 36, in handle
    datasource.sync()
  File "/opt/netbox/netbox/core/models/data.py", line 155, in sync
    with backend.fetch() as local_path:
  File "/usr/lib/python3.10/contextlib.py", line 135, in __enter__
    return next(self.gen)
  File "/opt/netbox/netbox/core/data_backends.py", line 108, in fetch
    raise SyncError(f"Fetching remote data failed ({type(e).__name__}): {e} {self.params}")
core.exceptions.SyncError: Fetching remote data failed (NotImplementedError): Setting password not supported by SubprocessSSHVendor. {'branch': 'main', 'password': '', 'username': 'git'}

It the password parameter is removed too from netbox/core/data_backends.py#L104 the sync works with git over ssh and ssh key authentication.

@jiuka jiuka added the type: bug A confirmed report of unexpected behavior in the application label May 4, 2023
@DanSheps
Copy link
Member

DanSheps commented May 4, 2023

I think the best we can do here is add some validation to prevent both using the username field and including the username within the URL, however I don't know if we actually want to do that as that seems like a lot of extra work (we might have to write a separate parser for the URL) for very little gain.

The second case should probably be handled better however I feel that this should be more documentation then a bug itself. "You can't use a username in the URL and the username/password backend fields."

@jiuka
Copy link
Author

jiuka commented May 4, 2023

Both bug get trigger regardless if you enter a username and/or password in the backup parameters.
I think it would be necessary to build a dict with the parameters and not add the username and password parameter if the scheme is ssh. Something like:

    @contextmanager
    def fetch(self):
        local_path = tempfile.TemporaryDirectory()

        username = self.params.get('username')
        password = self.params.get('password')
        branch = self.params.get('branch')
        config = StackedConfig.default()

        if settings.HTTP_PROXIES and self.url_scheme in ('http', 'https'):
            if proxy := settings.HTTP_PROXIES.get(self.url_scheme):
                config.set("http", "proxy", proxy)

        clone_kwargs = dict(
            depth=1,
            branch=branch,
            username=username,
            password=password,
            config=config,
            quiet=True
        )

        if self.url_scheme in ('git'):
            del clone_kwargs['username']
            del clone_kwargs['password']

        logger.debug(f"Cloning git repo: {self.url}")
        try:
            porcelain.clone(
                self.url, local_path.name, errstream=porcelain.NoneStream(), **clone_kwargs
            )
        except BaseException as e:
            raise SyncError(f"Fetching remote data failed ({type(e).__name__}): {e}")

        yield local_path.name

        local_path.cleanup()

@tobiasge
Copy link
Member

tobiasge commented May 4, 2023

I will create a PR

tobiasge added a commit to tobiasge/netbox that referenced this issue May 4, 2023
@jeremystretch jeremystretch added the status: accepted This issue has been accepted for implementation label May 4, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: accepted This issue has been accepted for implementation type: bug A confirmed report of unexpected behavior in the application
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants