haxsaw / hikaru Goto Github PK
View Code? Open in Web Editor NEWMove smoothly between Kubernetes YAML and Python for creating/updating/componentizing configurations.
License: MIT License
Move smoothly between Kubernetes YAML and Python for creating/updating/componentizing configurations.
License: MIT License
When generating Python code, values keep coming out quoted, regardless if they are string values or not. These need to be quoted only when they are strings.
When running basic_tests.py I get the following error. All other tests pass successfully:
test74 failed with should have gotten a ValueError, <class 'AssertionError'>
Process finished with exit code 0
Hikaru tests were originally written using nose but shifted to pytest due to pytest supporting nose-style tests. However, recent environment rebuilds reveal that nose support has been removed from pytest and now hikaru's tests no longer work properly unless run by an old version of pytest. The tests need to be updated to allow them to be run by current versions of pytest.
Thanks for the new version. It's great!
When trying yo patch/replace an existing Kubernetes object (configmap/deployment etc), the api returns an error regarding the creationTimestamp field (see the error below)
Removing this field from the generated 'clean_dict' before saving solved it, but I'm not sure this is the correct solution
Code sample:
dep: Deployment = Deployment.readNamespacedDeployment("my-deployment", "default").obj
dep.spec.replicas += 1
dep.patchNamespacedDeployment("my-deployment", "default")
error:
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"ConfigMap in version "v1" cannot be handled as a ConfigMap: v1.ConfigMap.Data: ObjectMeta: v1.ObjectMeta.UID: SelfLink: ResourceVersion: Namespace: Name: CreationTimestamp: unmarshalerDecoder: parsing time "2021-05-15T12:53:45" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00", error found in #10 byte of ...|T12:53:45", "name": |..., bigger context ...|data": {"creationTimestamp": "2021-05-15T12:53:45", "name": "jobs-states", "namespace": "robusta", "|...","reason":"BadRequest","code":400}
stack trace:
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/hikaru/model/rel_1_16/v1/v1.py", line 12134, in replaceNamespacedConfigMap
result = the_method(**all_args)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/kubernetes/client/api/core_v1_api.py", line 25568, in replace_namespaced_config_map_with_http_info
return self.api_client.call_api(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/kubernetes/client/api_client.py", line 348, in call_api
return self.__call_api(resource_path, method,
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/kubernetes/client/api_client.py", line 180, in __call_api
response_data = self.request(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/kubernetes/client/api_client.py", line 399, in request
return self.rest_client.PUT(url,
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/kubernetes/client/rest.py", line 284, in PUT
return self.request("PUT", url,
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/kubernetes/client/rest.py", line 233, in request
raise ApiException(http_resp=r)
kubernetes.client.exceptions.ApiException: (400)
Reason: Bad Request
HikaruBase would benefit from the addition of a 'merge()' method that would take data from another instance of the same Hikaru class and merge it into self. You should be able to select whether you want None values from the other to be put into self (full overwrite) or to just copy over non-None values.
Hi @haxsaw
The replacement in https://github.com/haxsaw/hikaru/blob/main/hikaru/generate.py#L84 may implicitely convert a custom label my_app
into my-app
, which is not needed in most scenarios. Is this a designed feature or a bug?
Add CRUD-style methods to those generated on HikaruDocumentBase subclasses. There may be cases where CRUD-like instance and static methods should be added; we need to consider what it means to issue them on either (read() on an instance vs read() on the class, for example).
get_python_source
is the only place used black.format_file_contents
, black.FileMode
but this function is not for real world usage. it is better to move it to another file and black to dev requirements, so if any user need to use it in development envionment, he could install in seperately
Do you plan to support OpenShift?
If not please ignore or delete this issue.
If you do then I have converted the openshift swagger file to version 3 of the open API but it fails the build process with an error;
Traceback (most recent call last):
File "/usr/local/Cellar/[email protected]/3.9.4/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/local/Cellar/[email protected]/3.9.4/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/Users/anthcp/code/hikaru-oc/hikaru/build.py", line 556, in
build_it(sys.argv[1])
File "/Users/anthcp/code/hikaru-oc/hikaru/build.py", line 547, in build_it
load_stable(swagger_file)
File "/Users/anthcp/code/hikaru-oc/hikaru/build.py", line 218, in load_stable
for k, v in d["definitions"].items():
KeyError: 'definitions'
I have attached the swagger json file...
openapi-v3.json.gz
Hi Tom, my name is Tal and I work with @aantn in Robusta, where we use Hikaru as our kubernetes library.
It would be super nice if the functions exported by Hikaru will return a specific type rather than the general "Response" type.
For example, rather than writing:
from hikaru.model.rel_1_16.v1 import EventList
event_list: EventList = EventList.listNamespacedEvent("default").obj
It would be nice if one could simply write:
from hikaru.model.rel_1_16.v1 import EventList
event_list = EventList.listNamespacedEvent("default").obj
And still get the right type (EventList in this case), rather than the Optional[Any] type of Response.obj
(One possible implementation: rather than one Response type, Hikaru can maintain multiple Response[TYPE]
types - for example Response[EventList]
, Response[Pod]
etc. - and return the correct one from every function it exports)
Thanks :)
While trying to convert k8s Node event into hikaru Node object, I get the below error.
The node yaml contains:
daemonEndpoints:
kubeletEndpoint:
Port: 10250
To reproduce:
obj = hikaru.from_dict(some_node_dict, cls=Node)
Error:
obj = hikaru.from_dict(k8s_payload.obj, cls=model_class)
File "/usr/local/lib/python3.8/site-packages/hikaru/generate.py", line 243, in from_dict
doc = cls.from_yaml(yaml, translate=translate)
File "/usr/local/lib/python3.8/site-packages/hikaru/meta.py", line 455, in from_yaml
inst.process(yaml, translate=translate)
File "/usr/local/lib/python3.8/site-packages/hikaru/meta.py", line 832, in process
obj.process(val, translate=translate)
File "/usr/local/lib/python3.8/site-packages/hikaru/meta.py", line 832, in process
obj.process(val, translate=translate)
File "/usr/local/lib/python3.8/site-packages/hikaru/meta.py", line 832, in process
obj.process(val, translate=translate)
File "/usr/local/lib/python3.8/site-packages/hikaru/meta.py", line 816, in process
raise TypeError(f"{self.class.name} is missing {k8s_name}"
TypeError: DaemonEndpoint is missing port (originally port)
Hi @haxsaw,
I'm having some trouble importing the latest version of hikaru. I've tested on python3.9 and python3.11, both on an M1 Mac.
On python3.11:
$ python3.11 -m pip install --upgrade hikaru
Requirement already satisfied: hikaru in /opt/homebrew/lib/python3.9/site-packages (1.3.0)
Requirement already satisfied: hikaru-model-25>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.1)
Requirement already satisfied: hikaru-model-26>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.1)
Requirement already satisfied: hikaru-model-27>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.1)
Requirement already satisfied: hikaru-model-28>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.0)
Requirement already satisfied: hikaru-codegen>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.0)
Requirement already satisfied: hikaru-core>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru-codegen>=1.1.0->hikaru) (1.1.1)
...
$ python3.11
Python 3.11.6 (main, Nov 2 2023, 04:39:43) [Clang 14.0.3 (clang-1403.0.22.14.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from hikaru.model.rel_1_25 import Pod, ObjectMeta, PodSpec
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'Pod' from 'hikaru.model.rel_1_25' (unknown location)
On python3.9:
$ python3.9 -m pip install --upgrade hikaru
Requirement already satisfied: hikaru in /opt/homebrew/lib/python3.9/site-packages (1.3.0)
Requirement already satisfied: hikaru-model-25>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.1)
Requirement already satisfied: hikaru-model-26>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.1)
Requirement already satisfied: hikaru-model-27>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.1)
Requirement already satisfied: hikaru-model-28>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.0)
Requirement already satisfied: hikaru-codegen>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru) (1.1.0)
Requirement already satisfied: hikaru-core>=1.1.0 in /opt/homebrew/lib/python3.9/site-packages (from hikaru-codegen>=1.1.0->hikaru) (1.1.1)
...
$ python3.9
>>> from hikaru.model.rel_1_25 import Pod, ObjectMeta, PodSpec
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/homebrew/lib/python3.9/site-packages/hikaru/model/rel_1_25/__init__.py", line 33, in <module>
from .deprecations import *
File "/opt/homebrew/lib/python3.9/site-packages/hikaru/model/rel_1_25/deprecations.py", line 1, in <module>
from hikaru.generate import add_deprecations_for_release
ModuleNotFoundError: No module named 'hikaru.generate'
Any ideas?
In the course of researching support for exposing K8s 'watch' functionality, it was discovered that the 'list' operations are not being consistently attached to classes as methods. For example, listNamespacedJob() is a method on the JobList class, but listJobForAllNamespaces() is a method on the Job class. The intent was that methods that return a list be attached to the list class themselves, not the class that are items in the list. For the sake of consistency, new models are needed that establish these methods on the proper class, and any changes that are made must be documented to aid anyone who has to alter code due to this method refactor.
Scenario 1: After registering a custom Pod class, API methods returning a PodList contain Pods and not the custom class
I just came across Hikaru and am very interested. We're currently using cdk8s and are not happy with it, so looking for an alternative.
Our gripes with cdk8s aside: one thing it does very well is supporting crds and any kubernetes version. It does this by allowing users to "import" the spec from a cluster (https://cdk8s.io/docs/latest/cli/import/#crds). As far as I can tell, Hikaru relies on auto-generated code based on inspecting Kubernetes' openapi spec. I'm wondering if maintainers have considered opening up this code generation process so that users can "compile" their own hikaru module and thereby represent their own cluster versions and/or crds?
Hello! I'm having an issue when using the context manager with a CRD. I have the following code where I have got a new version of a CRD created, the code then reads the new_crd CRD and makes some updates and then calls the update()
CRUD method. When I run this the update actually works, but an exception is caught when the k8s API throws a 409.
try:
with rollback_cm(MyCRD(metadata=ObjectMeta(name=new_crd.metadata.name)).read()) as obj:
obj.spec = new_crd.spec
obj.metadata.annotations = new_crd.metadata.annotations
obj.status = {"status": "updated"}
obj.update(dry_run=dry_run_directive)
except Exception:
# always 409
In the logs I see:
[2024-03-05 19:54:12,783] kubernetes.client.re [DEBUG ] response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Operation cannot be fulfilled on mycrd.app.com \"my-app-0
\": the object has been modified; please apply your changes to the latest version and try again","reason":"Conflict","details":{"name":"my-app-0","group":"app.com","kind":"mycrd"},"code":409}
But like I said, the change has been applied. Is this something anyone has seen before?
I am using hikaru.model.rel_1_26.v1
The values pod.status.podIP
and pod.status.hostIP
returned by pod = Pod.readNamespacedPod()
or pod.read()
are always None
when the pod is actively running in a cluster.
I believe the issue occurs here:
Lines 988 to 992 in d1a00be
The pod status JSON from underlying Kubernetes call has the keys pod_ip
and host_ip
, while the field names in PodStatus
are podIP
and hostIP
. It looks like the code in the link tries to find the key camel_to_pep8(class_field_name)
in the JSON response, but camel_to_pep8(podIP)
and camel_to_pep8(hostIP)
return pod_i_p
and host_i_p
Are there any plans on releasing new versions?
"Black" version < 22.3.0 has issues and conflicts with "click" >= 8.1.0. Thus the version range that is pinned is causing conflicts in many of our projects.
Additionally, "Black" is a code quality tool - thus is should be specified in "extras_require" section, not the main "install_requires" - since it is not actually needed to install the package externally.
I recommend to create a "dev" section under "extras_require" and pin "black" there if needed - or unpin it alltogether.
I think VolumeSnapshot is missing from the Hikaru API.
I'm running an older version of Hikaru and it doesn't appear there. I also searched the Hikaru docs for newer releases and couldn't find it.
Is it possible this is missing?
https://kubernetes.io/docs/concepts/storage/volume-snapshots/
https://kubernetes.io/blog/2020/12/10/kubernetes-1.20-volume-snapshot-moves-to-ga/
test1 = hikaru.load_full_yaml(path='./hikaru_test/1.yaml')
print(hikaru.get_yaml(test1[0]))
1.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: hello-kiamol-3
spec:
containers:
# test_comment
- name: web # test_comment_2
image: kiamol/ch02-hello-kiamol
output
---
apiVersion: v1
kind: Pod
metadata: {name: hello-kiamol-3}
spec:
containers:
- {image: kiamol/ch02-hello-kiamol, name: web}
Is it possible to preserve comments and formattion (using ruamel.yaml CommentedMap or something similar)? The use case here is quite straightforward - to be able to load, modify and dump k8s objects back to their original storage (which is yaml file in git)
Hey! I'm diffing two objects and getting a Type mismatch when the field is None in one object and has a value in the other. I think it would make more sense if this was a Value mismatch and not a type mismatch.
Example:
[DiffDetail(cls=<class 'hikaru.model.v1.ObjectMeta'>, attrname='deletionGracePeriodSeconds', path=['metadata', 'deletionGracePeriodSeconds'], report="Type mismatch:self.deletionGracePeriodSeconds is a <class 'int'> but other's is a <class 'NoneType'>"),
DiffDetail(cls=<class 'hikaru.model.v1.ObjectMeta'>, attrname='deletionTimestamp', path=['metadata', 'deletionTimestamp'], report="Type mismatch:self.deletionTimestamp is a <class 'str'> but other's is a <class 'NoneType'>"),
Any thoughts?
Right now you create a pod like this:
Pod(apiVersion='v1', kind='Pod',
metadata=ObjectMeta(name='hello-kiamol-3'),
spec=PodSpec(
containers=[Container(name='web', image='kiamol/ch02-hello-kiamol') ]
)
)
Is there a use-case where you would want to give the kind field a value that doesn't match the name of the type itself? Can this field be automatically set?
Hi There,
Based on how Hikaru is using OpenAPI/Swagger specs to generate types, would you consider supporting Argo Workflows? (Swagger 2.0 Spec).
If not, is there any way to generate my own types and use them with Hikaru?
Thanks!
The following test doesn't pass because object_at_path can't traverse dictionaries. I think it is useful to support and can open a PR for this if you like.
def test122():
"""
test that you can run object_at_path on the path returned by diff()
"""
pod = Pod(
spec=PodSpec(
containers=[
Container(name="a", resources=ResourceRequirements(limits={"foo": "bar"}))
]
)
)
pod2 = copy.deepcopy(pod)
pod2.spec.containers[0].resources.limits["foo"] = "blah"
diff = pod.diff(pod2)
print(diff)
print("object at path is", pod.object_at_path(diff[0].path))
So it seems that the supplied body argument isn't being supplied to the lower-level Kubernetes client API call. Need to investigate the logic that is preventing this from being rendered.
Hi,
Do You plan somewhere in future to provide full object checking?
It would be awesome to check if created object fulfil all the criteria, like max 64 characters in pod name etc.
Something similar as kubectl apply --dry-run to validate yamls.
On my local machine, the following fails:
from hikaru.model.rel_1_26 import ContainerStatus, Pod
with a strange error:
ImportError: cannot import name 'ContainerStatus' from 'hikaru.model.rel_1_26' (/Users/natanyellin/Library/Caches/pypoetry/virtualenvs/robusta-cli-k1xMhET--py3.9/lib/python3.9/site-packages/hikaru/model/rel_1_26/__init__.py)
Of course, ContainerStatus
does in fact exist in the right place.
If I patch site-packages/hikaru/model/rel_1_26/v1/__init__.py
as follows:
try:
from .v1 import *
except ImportError as e: # pragma: no cover
print("Whoops", e)
pass
We discover the real cause:
Whoops cannot import name 'CertificatesV1Api' from 'kubernetes.client' (/Users/natanyellin/Library/Caches/pypoetry/virtualenvs/robusta-cli-k1xMhET--py3.9/lib/python3.9/site-packages/kubernetes/client/__init__.py)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'ContainerStatus' from 'hikaru.model.rel_1_26' (/Users/natanyellin/Library/Caches/pypoetry/virtualenvs/robusta-cli-k1xMhET--py3.9/lib/python3.9/site-packages/hikaru/model/rel_1_26/__init__.py)
hikaru is trying to import CertificatesV1Api
which doesn't exist in the minimum version of kubernetes-client
that hikaru requires. (All of hikaru's python dependencies are satisfied on my machine, although some libraries like kubernetes-client
are running a compatible but not latest version.)
If I update my local kubernetes-client
version to the latest this problem resolves itself.
kubernetes-client
version (not sure what's the real minimum, just know that latest works for me)pass
on ImportErrors? It makes troubleshooting stuff like this a little hard.Hikaru doesn't recognize the field Pod.spec.containers[*].livenessProbe.exec.
How to reproduce:
$ kubectl apply -f https://raw.githubusercontent.com/robusta-dev/kubernetes-demos/main/liveness_probe_fail/failing_liveness_probe.yaml
$ python3.9
>>> from kubernetes import client, config
>>> import hikaru
>>> from hikaru import *
>>> from hikaru.model.rel_1_25 import *
>>> config.load_kube_config()
>>> p = Pod().read(name='order-processor', namespace='default')
>>> print(p.spec.containers[0].livenessProbe)
Probe(exec=None, failureThreshold=1000, grpc=None, httpGet=None, initialDelaySeconds=5, periodSeconds=5, successThreshold=1, tcpSocket=None, terminationGracePeriodSeconds=None, timeoutSeconds=1)
As you can see, the exec field is missing from the liveness probe in Hikaru.
Here is the complete code to reproduce for convenience:
from kubernetes import client, config
import hikaru
from hikaru import *
from hikaru.model.rel_1_25 import *
config.load_kube_config()
p = Pod().read(name='order-processor', namespace='default')
print(p.spec.containers[0].livenessProbe)
Example:
from hikaru.model.rel_1_16 import *
d = Deployment(metadata=ObjectMeta(name='somename', namespace='somens')).read()
print(d.metadata.selfLink)
I tested this on the latest released version of Hikaru. Let me know if you need more information to reproduce.
As a sidenote, thank you very much for the work you did on the CRUD API. We've updated most of our code to use Hikaru's CRUD methods instead of directly using the K8s Python client. We're very happy with the API.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.