Skip to content
This repository was archived by the owner on Mar 13, 2022. It is now read-only.

Dynamic Client - #56

Merged
k8s-ci-robot merged 3 commits into
kubernetes-client:masterfrom
fabianvf:dynamic-client
Aug 12, 2019
Merged

k8s-ci-robot merged 3 commits into
kubernetes-client:masterfrom
fabianvf:dynamic-client

Conversation

@fabianvf

@fabianvf fabianvf commented Apr 9, 2018 •

Copy link
Copy Markdown
Contributor

Still TODO:

  • Support for subresources
  • Support for async
  • Delete options
  • Ability to easily retrigger discovery
  • Documentation
  • Tests

@codecov-io

codecov-io commented Apr 9, 2018 •

Copy link
Copy Markdown

Codecov Report

Merging #56 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master      #56   +/-   ##
=======================================
  Coverage   91.85%   91.85%           
=======================================
  Files          11       11           
  Lines         994      994           
=======================================
  Hits          913      913           
  Misses         81       81

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 24a0ff2...788d114. Read the comment docs.

@fabianvf

Copy link
Copy Markdown
Contributor Author

@mbohlool

@mbohlool

mbohlool commented May 4, 2018

Copy link
Copy Markdown
Contributor

@yliaog @roycaihw

@fabianvf fabianvf changed the title [WIP] Dynamic Client Dynamic Client May 4, 2018

@roycaihw roycaihw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! I left some comments :)

Comment thread dynamic/client.py Outdated
from kubernetes.client.api_client import ApiClient
from kubernetes.client.rest import ApiException

from openshift.dynamic.exceptions import ResourceNotFoundError, ResourceNotUniqueError, api_exception

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module path needs to be changed

Comment thread dynamic/client.py Outdated
def group_version(self):
if self.group:
return '{}/{}'.format(self.group, self.api_version)
return self.api_version

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: '/'.join(filter(None, [self.group, self.api_version])) like Line112?

Comment thread dynamic/client.py Outdated
kind: The kind of the resource
arbitrary arguments (see below), in random order

The arbitrary arguments can be any valid attribute for an openshift.dynamic.Resource object

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: update the module path

Comment thread dynamic/client.py Outdated
def path(self, name=None, namespace=None):
url_type = []
path_params = {}
if self.namespaced and namespace:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we catch the case where namespaced is set but namespace is None?

or does ensure_namespace rule out that case already?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if namespaced is set and namespace is None, then we can still construct a valid path (api/v1/pods for example)

Comment thread dynamic/client.py Outdated
'base': '/{}/{}'.format(full_prefix, self.name),
'namespaced_base': '/{}/namespaces/{{namespace}}/{}'.format(full_prefix, self.name),
'full': '/{}/{}/{{name}}'.format(full_prefix, self.name),
'namespaced_full': '/{}/namespaces/{{namespace}}/{}/{{name}}'.format(full_prefix, self.name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we determine if the resource is cluster-scoped or namespaced using self.namespaced here and only return two urls base and full?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can access namespaced resources without providing a namespace (ie, list all pods in every namespace, etc), so I don't think we should

Comment thread dynamic/client.py Outdated
content_type = self.client.\
select_header_content_type(['application/json-patch+json', 'application/merge-patch+json', 'application/strategic-merge-patch+json'])

return self.request('patch', path, body=body, content_type=content_type)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass **kwargs to self.request

Comment thread dynamic/client.py
Comment thread dynamic/client.py
@meta_request
def delete(self, resource, name=None, namespace=None, label_selector=None, field_selector=None, **kwargs):
if not (name or label_selector or field_selector):
raise ValueError("At least one of name|label_selector|field_selector is required")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the design doc, the following actions are marked as TODO: update, watch, deletecollection, proxy. I see update has been implemented (replace). I'm just curious if we don't want to have deletecollection for the first iteration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the only reason I didn't yet implement deletecollection is that I'm not familiar with it, would love to get it in

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still TODO

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to add deletecollection as a followup

Comment thread dynamic/client.py Outdated
full_prefix = '{}/{}'.format(self.prefix, self.group_version)
return {
'full': '/{}/{}/{{name}}/{}'.format(full_prefix, self.parent.name, self.subresource),
'namespaced_full': '/{}/namespaces/{{namespace}}/{}/{{name}}/{}'.format(full_prefix, self.parent.name, self.subresource)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: if we could check self.namespaced and combine the two urls into one

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above response

Comment thread dynamic/client.py Outdated
def _load_server_info(self):
self.__version = {'kubernetes': load_json(self.request('get', '/version'))}
try:
self.__version['openshift'] = load_json(self.request('get', '/version/openshift'))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this is not specific to kubernetes cluster api discovery. Not sure how we want organize the code. Looping in @yliaog @mbohlool

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can go ahead and take it out, this belongs in openshift specific code not upstream

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jul 30, 2018
@fabianvf

Copy link
Copy Markdown
Contributor Author

@roycaihw rebased to keep up to date with branch, any additional comments?

@fabianvf

fabianvf commented Aug 8, 2018

Copy link
Copy Markdown
Contributor Author

ping @roycaihw

@fabianvf

fabianvf commented Aug 8, 2018

Copy link
Copy Markdown
Contributor Author

We've also had some community interest in the other discussed dynamic implementation (the one that uses the OpenAPI spec for discovery), I haven't had time to look into it again yet but I'm hoping I'll get a chance for a second pass soon.

@roycaihw roycaihw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good to me in general. I left one nit and one question for clarification.

Comment thread dynamic/client.py Outdated
return self.request('post', path, body=body, **kwargs)

@meta_request
def delete(self, resource, name=None, namespace=None, label_selector=None, field_selector=None, **kwargs):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k8s delete requests can have body of type DeleteOptions as alternative of some query parameters, although it's not a good practice to send delete request with body I suppose.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, this should definitely support delete options.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still TODO

Comment thread dynamic/client.py Outdated
self.client = client
self.configuration = client.configuration
self._load_server_info()
self.__resources = ResourceContainer(self.parse_api_groups())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC people need to create another ResourceContainer with client.parse_api_groups() when they want to re-discover new CRDs and aggregated APIs - self.__resources only records the resources that exist when the dynamic client gets created - is that correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I'll break this stuff out into a discovery() method so that it can be called repeatedly

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll break this stuff out into a discovery() method so that it can be called repeatedly

This can be done in a separate PR.

@roycaihw

Copy link
Copy Markdown
Member

I think this PR will be good to go after @fabianvf adds body to delete requests. @yliaog @mbohlool Any other comments?

This dynamic client should also be e2e tested (something like test_client.py), probably in another PR.

Comment thread dynamic/client.py
from functools import partial
import yaml
from pprint import pformat
from kubernetes.client.rest import ApiException

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to have the import above be ordered?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I can clean that up

Comment thread dynamic/exceptions.py
503: ServiceUnavailableError,
504: ServerTimeoutError,
}.get(e.status, DynamicApiError)(e, tb)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if just want to add traceback, why do you need to add all these specific HTTP errors (BadRequestError, UnauthorizedError, ...)? Is DynamicApiError alone not enough for the purpose?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to expose errors that correspond to the HTTP errors we receive, it provides a cleaner way to handle errors when consuming the client (since you can just catch a NotFoundError rather than catching a DynamicApiError and checking the status code). Catching a generic DynamicApiError and checking the code still works if the user prefers to handle it that way.

Comment thread dynamic/client.py Outdated
header_params['Accept'] = self.client.select_header_accept([
'application/json',
'application/yaml',
'application/vnd.kubernetes.protobuf'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think protobuf is supported in python client, better to remove it here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, good call

@fabianvf

fabianvf commented Sep 5, 2018

Copy link
Copy Markdown
Contributor Author

sorry, I've been on PTO + planning meetings the last few weeks, I'll try and carve up some time to clean all this up sometime this week or next

@fabianvf

Copy link
Copy Markdown
Contributor Author

We're actually doing a little bit of a rework of the dynamic client in openshift, driven by user feedback. I think I might hold off a bit on updating this PR, so that I can bring those improvements in

@micw523

micw523 commented Mar 19, 2019

Copy link
Copy Markdown
Contributor

@fabianvf I see that you're working on a dynamic client for OpenShift. Are there any plans to backport the dynamic client to this library?

@fabianvf

Copy link
Copy Markdown
Contributor Author

Yes, there's actually almost nothing specific to openshift in the client. There was a lot of churn so I put this PR on hold while we stabilized a bit, now it's mostly a matter of finding the time to bring in the relevant new stuff.

@fejta-bot

Copy link
Copy Markdown

Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle stale

@k8s-ci-robot k8s-ci-robot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Jun 17, 2019
@micw523

micw523 commented Jun 17, 2019 via email •

Copy link
Copy Markdown
Contributor

@k8s-ci-robot k8s-ci-robot removed the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Jun 17, 2019
@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jun 28, 2019
@roycaihw

roycaihw commented Aug 6, 2019

Copy link
Copy Markdown
Member

/lgtm
/approve

Thanks a lot for working on this! Will merge after the test failure gets resolved kubernetes-client/python#919

@k8s-ci-robot k8s-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Aug 6, 2019
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: fabianvf, roycaihw

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 6, 2019
@yliaog

yliaog commented Aug 7, 2019

Copy link
Copy Markdown
Contributor

i have a meta request, could you please squash the commits to a few logical commits?

@k8s-ci-robot k8s-ci-robot removed the lgtm Indicates that a PR is ready to be merged. label Aug 10, 2019
@roycaihw

Copy link
Copy Markdown
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Aug 12, 2019
@k8s-ci-robot
k8s-ci-robot merged commit 4b8e89f into kubernetes-client:master Aug 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm Indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants