Skip to content

Commit b7d7c2d

Browse files
committed
fixes(api) allow no v2 api
Allow client without no V2 api Closes #220
1 parent 77c1923 commit b7d7c2d

39 files changed

+166
-88
lines changed

.github/workflows/pythonpackage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
max-parallel: 1
1515
matrix:
16-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
16+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
1717

1818
steps:
1919
- uses: actions/checkout@v4

main/cloudfoundry_client/client.py

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,28 @@
5252
class Info:
5353
def __init__(
5454
self,
55-
api_v2_version: str,
55+
api_v2_url: str,
56+
api_v3_url: str,
5657
authorization_endpoint: str,
5758
api_endpoint: str,
5859
doppler_endpoint: Optional[str],
5960
log_stream_endpoint: Optional[str],
6061
):
61-
self.api_v2_version = api_v2_version
62+
self._api_v2_url = api_v2_url
63+
self._api_v3_url = api_v3_url
6264
self.authorization_endpoint = authorization_endpoint
6365
self.api_endpoint = api_endpoint
6466
self.doppler_endpoint = doppler_endpoint
6567
self.log_stream_endpoint = log_stream_endpoint
6668

69+
@property
70+
def api_v2_url(self) -> Optional[str]:
71+
return self._api_v2_url
72+
73+
@property
74+
def api_v3_url(self) -> Optional[str]:
75+
return self._api_v3_url
76+
6777

6878
class NetworkingV1External(object):
6979
def __init__(self, target_endpoint: str, credential_manager: "CloudFoundryClient"):
@@ -83,18 +93,18 @@ def __init__(self, target_endpoint: str, credential_manager: "CloudFoundryClient
8393
self.service_plans = ServicePlanManagerV2(target_endpoint, credential_manager)
8494
# Default implementations
8595
self.event = EventManager(target_endpoint, credential_manager)
86-
self.organizations = EntityManagerV2(target_endpoint, credential_manager, "/v2/organizations")
87-
self.private_domains = EntityManagerV2(target_endpoint, credential_manager, "/v2/private_domains")
96+
self.organizations = EntityManagerV2(target_endpoint, credential_manager, "/organizations")
97+
self.private_domains = EntityManagerV2(target_endpoint, credential_manager, "/private_domains")
8898
self.routes = RouteManager(target_endpoint, credential_manager)
89-
self.services = EntityManagerV2(target_endpoint, credential_manager, "/v2/services")
90-
self.shared_domains = EntityManagerV2(target_endpoint, credential_manager, "/v2/shared_domains")
99+
self.services = EntityManagerV2(target_endpoint, credential_manager, "/services")
100+
self.shared_domains = EntityManagerV2(target_endpoint, credential_manager, "/shared_domains")
91101
self.spaces = SpaceManagerV2(target_endpoint, credential_manager)
92-
self.stacks = EntityManagerV2(target_endpoint, credential_manager, "/v2/stacks")
102+
self.stacks = EntityManagerV2(target_endpoint, credential_manager, "/stacks")
93103
self.user_provided_service_instances = EntityManagerV2(
94-
target_endpoint, credential_manager, "/v2/user_provided_service_instances"
104+
target_endpoint, credential_manager, "/user_provided_service_instances"
95105
)
96-
self.security_groups = EntityManagerV2(target_endpoint, credential_manager, "/v2/security_groups")
97-
self.users = EntityManagerV2(target_endpoint, credential_manager, "/v2/users")
106+
self.security_groups = EntityManagerV2(target_endpoint, credential_manager, "/security_groups")
107+
self.users = EntityManagerV2(target_endpoint, credential_manager, "/users")
98108
# Resources implementation used by push operation
99109
self.resources = ResourceManager(target_endpoint, credential_manager)
100110

@@ -146,8 +156,6 @@ def __init__(self, target_endpoint: str, client_id: str = "cf", client_secret: s
146156
self.login_hint = kwargs.get("login_hint")
147157
target_endpoint_trimmed = target_endpoint.rstrip("/")
148158
info = self._get_info(target_endpoint_trimmed, proxy, verify=verify)
149-
if not info.api_v2_version.startswith("2."):
150-
raise AssertionError("Only version 2 is supported for now. Found %s" % info.api_v2_version)
151159
service_information = ServiceInformation(
152160
None, "%s/oauth/token" % info.authorization_endpoint, client_id, client_secret, [], verify
153161
)
@@ -156,8 +164,16 @@ def __init__(self, target_endpoint: str, client_id: str = "cf", client_secret: s
156164
proxies=proxy,
157165
user_agent=kwargs.get("user_agent", "cf-python-client")
158166
)
159-
self.v2 = V2(target_endpoint_trimmed, self)
160-
self.v3 = V3(target_endpoint_trimmed, self)
167+
self._v2 = (
168+
V2(info.api_v2_url, self)
169+
if info.api_v2_url is not None
170+
else None
171+
)
172+
self._v3 = (
173+
V3(info.api_v3_url, self)
174+
if info.api_v3_url is not None
175+
else None
176+
)
161177
self._doppler = (
162178
DopplerClient(
163179
info.doppler_endpoint,
@@ -181,6 +197,18 @@ def __init__(self, target_endpoint: str, client_id: str = "cf", client_secret: s
181197
self.networking_v1_external = NetworkingV1External(target_endpoint_trimmed, self)
182198
self.info = info
183199

200+
@property
201+
def v2(self) -> V2:
202+
if self._v2 is None:
203+
raise NotImplementedError("No V2 endpoint for this instance")
204+
return self._v2
205+
206+
@property
207+
def v3(self) -> V3:
208+
if self._v3 is None:
209+
raise NotImplementedError("No V3 endpoint for this instance")
210+
return self._v3
211+
184212
@property
185213
def doppler(self) -> DopplerClient:
186214
if self._doppler is None:
@@ -194,7 +222,6 @@ def rlpgateway(self):
194222
if self._rlpgateway is None:
195223
raise NotImplementedError("No RLP gateway endpoint for this instance")
196224
else:
197-
198225
return self._rlpgateway
199226

200227
def _get_info(self, target_endpoint: str, proxy: Optional[dict] = None, verify: bool = True) -> Info:
@@ -206,8 +233,11 @@ def _get_info(self, target_endpoint: str, proxy: Optional[dict] = None, verify:
206233
root_links = root_info["links"]
207234
logging = root_links.get("logging")
208235
log_stream = root_links.get("log_stream")
236+
cloud_controller_v2 = root_links.get("cloud_controller_v2")
237+
cloud_controller_v3 = root_links.get("cloud_controller_v3")
209238
return Info(
210-
root_links["cloud_controller_v2"]["meta"]["version"],
239+
cloud_controller_v2["href"] if cloud_controller_v2 is not None else None,
240+
cloud_controller_v3["href"] if cloud_controller_v3 is not None else None,
211241
self._resolve_login_endpoint(root_links),
212242
target_endpoint,
213243
logging.get("href") if logging is not None else None,

main/cloudfoundry_client/common_objects.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import json
2-
from typing import Callable, TypeVar, Generic, List, Union
2+
from typing import Callable, TypeVar, Generic, List, Optional
33

44

55
class Request(dict):
@@ -21,7 +21,7 @@ def __init__(self, *args, **kwargs):
2121
class Pagination(Generic[ENTITY]):
2222
def __init__(self, first_page: JsonObject,
2323
total_result: int,
24-
next_page_loader: Callable[[JsonObject], Union[None, JsonObject]],
24+
next_page_loader: Callable[[JsonObject], Optional[JsonObject]],
2525
resources_accessor: Callable[[JsonObject], List[JsonObject]],
2626
instance_creator: Callable[[JsonObject], ENTITY]):
2727
self._first_page = first_page

main/cloudfoundry_client/v2/apps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class AppManager(EntityManager):
7777

7878
def __init__(self, target_endpoint: str, client: "CloudFoundryClient"):
7979
super(AppManager, self).__init__(
80-
target_endpoint, client, "/v2/apps", lambda pairs: Application(target_endpoint, client, pairs)
80+
target_endpoint, client, "/apps", lambda pairs: Application(target_endpoint, client, pairs)
8181
)
8282

8383
def get_stats(self, application_guid: str) -> Dict[str, JsonObject]:

main/cloudfoundry_client/v2/buildpacks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class BuildpackManager(EntityManager):
1010
def __init__(self, target_endpoint: str, client: "CloudFoundryClient"):
11-
super(BuildpackManager, self).__init__(target_endpoint, client, "/v2/buildpacks")
11+
super(BuildpackManager, self).__init__(target_endpoint, client, "/buildpacks")
1212

1313
def update(self, buildpack_guid: str, parameters: dict) -> Entity:
1414
return super(BuildpackManager, self)._update(buildpack_guid, parameters)

main/cloudfoundry_client/v2/entities.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from functools import partial, reduce
2-
from typing import Callable, List, Tuple, Any, Optional, TYPE_CHECKING, Union
2+
from typing import Callable, List, Tuple, Any, Optional, TYPE_CHECKING
33
from urllib.parse import quote
44
from requests import Response
55

@@ -68,7 +68,7 @@ def _list(self, requested_path: str, entity_builder: Optional[EntityBuilder] = N
6868
lambda page: page["resources"],
6969
lambda json_object: current_builder(list(json_object.items())))
7070

71-
def _next_page(self, current_page: JsonObject) -> Union[None, JsonObject]:
71+
def _next_page(self, current_page: JsonObject) -> Optional[JsonObject]:
7272
next_url = current_page.get("next_url")
7373
if next_url is None:
7474
return None

main/cloudfoundry_client/v2/events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class EventManager(EntityManager):
1010
def __init__(self, target_endpoint: str, client: "CloudFoundryClient"):
11-
super(EventManager, self).__init__(target_endpoint, client, "/v2/events")
11+
super(EventManager, self).__init__(target_endpoint, client, "/events")
1212

1313
def list_by_type(self, event_type: str) -> Generator[Entity, None, None]:
1414
return self._list(self.entity_uri, type=event_type)

main/cloudfoundry_client/v2/jobs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ def __init__(self, target_endpoint: str, client: "CloudFoundryClient"):
1212
self.client = client
1313

1414
def get(self, job_guid: str) -> JsonObject:
15-
return self.client.get("%s/v2/jobs/%s" % (self.target_endpoint, job_guid)).json(object_pairs_hook=JsonObject)
15+
return self.client.get("%s/jobs/%s" % (self.target_endpoint, job_guid)).json(object_pairs_hook=JsonObject)

main/cloudfoundry_client/v2/resources.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ def __init__(self, target_endpoint: str, client: "CloudFoundryClient"):
1212
self.client = client
1313

1414
def match(self, items: List[dict]) -> List[JsonObject]:
15-
response = self.client.put("%s/v2/resource_match" % self.client.info.api_endpoint, json=items)
15+
response = self.client.put("%s/resource_match" % self.client.info.api_endpoint, json=items)
1616
return response.json(object_pairs_hook=JsonObject)

main/cloudfoundry_client/v2/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class RouteManager(EntityManager):
1010
def __init__(self, target_endpoint: str, client: "CloudFoundryClient"):
11-
super(RouteManager, self).__init__(target_endpoint, client, "/v2/routes")
11+
super(RouteManager, self).__init__(target_endpoint, client, "/routes")
1212

1313
def create_tcp_route(self, domain_guid: str, space_guid: str, port: Optional[int] = None) -> Entity:
1414
request = self._request(domain_guid=domain_guid, space_guid=space_guid)

0 commit comments

Comments
 (0)