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

2.18.4 / 2.19.0 - Swagger generated Python api requires all fields for POST /endpoints #10198

Open
2 tasks done
Cyberunner23 opened this issue Aug 29, 2023 · 6 comments
Open
2 tasks done
Labels

Comments

@Cyberunner23
Copy link

Cyberunner23 commented Aug 29, 2023

Before you start please confirm the following.

Problem Description

When using the Python API generated from the Swagger spec, the EndpointsApi.endpoint_create which maps to POST /endpoints api call requires that all parameters are set, even though the Swagger Docs mention that only Name, EndpointCreationType, and EdgeTunnelServerAddress is required. Which by the way, is the EdgeTunnelServerAddress field being required as intended?

Expected Behavior

The api call succeeds

Actual Behavior

An exception is thrown

Traceback (most recent call last):
  File "main.py", line 16, in <module>
    endpoints_api.endpoint_create(
TypeError: endpoint_create() missing 15 required positional arguments: 'url', 'public_url', 'group_id', 'tls', 'tls_skip_verify', 'tls_skip_client_verify', 'tlsca_cert_file', 'tls_cert_file', 'tls_key_file', 'azure_application_id', 'azure_tenant_id', 'azure_authentication_key', 'tag_ids', 'edge_checkin_interval', and 'gpus'

Steps to Reproduce

  1. Generate the Python api from the Swagger documentation
  2. Install the generated python api with pip
  3. Run the sample code below setting the PORTAINER_URL and API_KEY values
  4. Notice the exception

Command used to create the Python API

wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.43/swagger-codegen-cli-3.0.43.jar -O swagger-codegen-cli.jar
java -jar swagger-codegen-cli.jar generate -i https://api.swaggerhub.com/apis/portainer/portainer-ce/2.18.4?resolved=true -l python -DpackageName=portainer_api -o portainer_api

Sample Code:

from portainer_api.api_client import ApiClient
from portainer_api.configuration import Configuration
from portainer_api.api.endpoints_api import EndpointsApi

PORTAINER_URL: str = ""
API_KEY: str = ""

client_config = Configuration()
client_config.host = f"{PORTAINER_URL}/api"
client_config.verify_ssl = False
client_config.api_key['x-api-key'] = API_KEY

api_client = ApiClient(client_config)
endpoints_api = EndpointsApi(api_client)

endpoints_api.endpoint_create(
    name="TestEnvironment",
    endpoint_creation_type=1, # Local Environment
    edge_tunnel_server_address=""
)

Portainer logs or screenshots

Traceback (most recent call last):
  File "main.py", line 16, in <module>
    endpoints_api.endpoint_create(
TypeError: endpoint_create() missing 15 required positional arguments: 'url', 'public_url', 'group_id', 'tls', 'tls_skip_verify', 'tls_skip_client_verify', 'tlsca_cert_file', 'tls_cert_file', 'tls_key_file', 'azure_application_id', 'azure_tenant_id', 'azure_authentication_key', 'tag_ids', 'edge_checkin_interval', and 'gpus'

Portainer version

2.18.4

Portainer Edition

Community Edition (CE)

Platform and Version

Docker 24.0.4, docker-compose 2.7.0

OS and Architecture

Ubuntu 20.04, AMD64

Browser

No response

What command did you use to deploy Portainer?

docker-compose up

with the following docker-compose.yml

version: "3"
services:
    portainer:
        image: portainer/portainer-ce:2.18.4
        container_name: portainer
        ports:
          - 8000:8000
          - 9443:9443
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - portainer_data:/data
        network_mode: host

    portainer-agent:
        image: portainer/agent:2.18.4
        container_name: portainer_agent
        ports:
          - 9001:9001
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - portainer_data:/data
        network_mode: host

volumes:
    portainer_data:

Additional Information

No response

@Cyberunner23 Cyberunner23 changed the title 2.18.4 - Swagger generated Python api requires all fields for POST /endpoints 2.18.4 / 2.19.0 - Swagger generated Python api requires all fields for POST /endpoints Sep 1, 2023
@Cyberunner23
Copy link
Author

This issue persists with the 2.19.0 update

@jamescarppe
Copy link
Member

I've had some feedback from our engineering team, and they've pointed out that you're using swagger-codegen-cli@3.0.43 which is intended for Swagger/OpenAPI 3.x only. Our API docs are published using Swagger/OpenAPI 2.0, which is not directly supported (I suspect the spec conversion isn't working for our API docs) by the version you're using, as per their repo:

2.X and 3.X version lines of Swagger Codegen are available; 2.X (master branch) supports Swagger/OpenAPI version 2, while 3.X (3.0.0 branch) supports OpenAPI version 3 (and version 2 via spec conversion to version 3). Online generator of version 3.X supports both generation from Swagger/OpenAPI version 2 (by using engine + generators of 2.X) and version 3 specifications.

If you try with a 2.x version (for example 2.4.41) you should se a successful build:

wget https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/2.4.41/swagger-codegen-cli-2.4.41.jar -O swagger-codegen-cli.jar
java -jar swagger-codegen-cli.jar generate -i https://api.swaggerhub.com/apis/portainer/portainer-ce/2.19.5?resolved=true -l python -DpackageName=portainer_api -o portainer_api

@Cyberunner23
Copy link
Author

I am getting the same error with the swagger codegen 2.4.41. Arguments marked optional in the documentation are mandatory in the python generated code

@jamescarppe
Copy link
Member

It appears there may be a bug with API key authentication in 2.20 that our team are now looking into, so this could be part of the issue. I've been working with our engineering team and they've provided the following code snippet that should work using JWT authentication instead of API key auth as a workaround (it'll do the JWT generation itself, it just needs your credentials instead of a key) - are you able to give this a test and see if it works as you'd expect?

from portainer_api.api_client import ApiClient
from portainer_api.configuration import Configuration
from portainer_api.api.endpoints_api import EndpointsApi
from portainer_api.api.auth_api import AuthApi

PORTAINER_URL: str = "http://localhost:9000"

client_config = Configuration()
client_config.host = f"{PORTAINER_URL}/api"
client_config.verify_ssl = False

auth_json = {"username":"admin", "password":"mypasswordgoeshere"}

api_client = ApiClient(client_config)
auth_api = AuthApi(api_client)
auth_resp = auth_api.authenticate_user(
    body=auth_json
)

client_config.api_key['Authorization'] = f"Bearer {auth_resp.jwt}"
api_client = ApiClient(client_config)
endpoints_api = EndpointsApi(api_client)

endpoints_api.endpoint_create(
    name="TestEnvironment1",
    endpoint_creation_type=1, # Local Environment
    edge_tunnel_server_address=""
)

@Cyberunner23
Copy link
Author

My appologies, I seem to have made a mistake when running the swagger generation with swagger codegen 2.4.41. I have re-run it making sure I have a clean run and it does fix the issue

@jamescarppe
Copy link
Member

Great, thanks for following up. I'll close this issue (and the other one).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants