Releases: openyurtio/openyurt
Release list
v1.7.0
What's New
OTA Upgrade Supports Image Preheating for DaemonSet
OTA (Over-The-Air) upgrade is a new upgrade model for DaemonSet workloads introduced by OpenYurt. In previous versions, image pulling occurred synchronously during the Pod restart phase of the upgrade, making it a critical-path operation that directly contributed to service downtime, especially in edge environments with limited or unstable network connectivity.
In v1.7.0, OTA upgrade now supports image preheating, which decouples image pulling from the actual rollout cutover. A new ImagePreHeat controller is responsible for dispatching image preheating Jobs to edge nodes, allowing updated container images to be proactively downloaded before the upgrade is triggered. Two new Pod conditions (PodNeedUpgrade and PodImageReady) are introduced to track upgrade status and image readiness. Users can initiate preheating via a new OTA API endpoint (POST /openyurt.io/v1/namespaces/{ns}/pods/{podname}/imagepull). By pre-caching images ahead of the cutover, service interruption during the actual upgrade is minimized to near-zero.
#2482
#2474
Support Deploying Kubernetes Clusters Locally (K8s-on-K8s)
OpenYurt v1.7.0 introduces the ability to deploy a Kubernetes cluster on top of an existing OpenYurt cluster — referred to as K8s-on-K8s. This is particularly useful for scenarios such as testing, multi-tenant isolation, and edge IDC (Internet Data Center) deployments where a full bare-metal Kubernetes setup is not practical.
This release adds YAML-based templates for deploying tenant control-plane components (tenant-apiserver, tenant-controller-manager, tenant-scheduler, tenant-pki-generator, etcd) along with post-install configuration (kube-proxy, kubelet, rbac, bootstrap-secret). yurtadm now supports a local mode for joining IDC nodes into a K8s-on-K8s cluster, and YurtHub is optimized for local mode operation. A setup script (config/setup/K8s-on-K8s/setup.sh) is also provided for quick bootstrapping.
#4a1f0ab3
#ed2f7dbf
#3a03b00d
Label-Driven YurtHub Deployment via YurtNodeConversion
Previously, YurtHub installation and lifecycle management on edge nodes required manual intervention through yurtadm join or yurtadm reset commands. In v1.7.0, a new YurtNodeConversionController in yurt-manager enables label-driven YurtHub deployment and conversion. By applying a label to a node, users can trigger the automatic installation, configuration, and startup of YurtHub via systemd. The conversion and revert process now uses reusable host lifecycle helpers, enabling a fully declarative, controller-driven workflow for edge node onboarding and offboarding.
#249a6714
#f7645df8
#3e02cefa
Support Kubernetes v1.34
All k8s.io/xxx dependencies and related modules have been upgraded to v1.34.0, ensuring OpenYurt is fully compatible with Kubernetes v1.34. E2E testing has been updated to validate the upgrade against a Kubernetes v1.34 cluster. This upgrade also includes vendor dependency updates and Go linting fixes for compatibility with the latest toolchain.
#5cccf119
#7589921e
Other Notable changes
- Upgrade nodepool CRD to v1beta2 by @tnsimon in #2266
- Add hub election leader controller by @tnsimon in #2281
- Add hub leader config controller by @tnsimon in #2299
- Add hub leader RBAC controller by @tnsimon in #2328
- Add health checker for leader hub by @rambohe in #2310
- Support forward requests to leader hub for sharing pool scope metadata in nodepool by @rambohe in #2325
- Improve load balancer to support dynamically updating backends by @rambohe in #2314
- Add leader node names to v1beta2.nodepool by @tnsimon in #2297
- Rename enablePoolScopeMetadata to enableLeaderElections by @tnsimon in #2316
- Add consistent hashing strategy for yurthub by @tnsimon in #2359
- Improve proxy handler for yurthub and optimize metrics of multiplexer by @rambohe in #2345
- Refactor multiplexer by @zyjhtangtang in #2349
- Optimizing hub cache by @zyjhtangtang in #2423
- Improve direct clientsets for yurthub by @rambohe in #2285
- Improve readiness probe for yurthub component by @rambohe in #2284
- Improve config and start process of yurthub component by @rambohe in #2303
- Improve yurthub configmap management by @rambohe in #2275
- Systemd component support for yurthub by @yuyushui66 in #2449
- Release assets add yurthub binary by @zyjhtangtang in #2448
- Remove YurtAppOverrider by @jessie in #2280
- Remove yurt-coordinator from yurthub by @rambohe in #2276
- Refactor: remove yurt-coordinator-cert controller from yurt-manager by @lixx in #2322
- Refactor yurt-manager: update CRD categories and remove YurtAppDaemon related code by @lu Chen in #2320
- Deprecate yurtmanager delegate lease controller by @tnsimon in #2308
- Deprecate YurtAppDaemon controller and webhook by @tnsimon in #2309
- Remove yurt-coordinator from Helm charts by @zyjhtangtang in #2477
- Support Kubernetes v1.32 by @zyjhtangtang in #2387
- Use autonomy duration label by @tnsimon in #2313
- Update Go version by @tnsimon in #2357
- Upgrade upload-artifact to v4 by @zyjhtangtang in #2336
- Update codecov-action by @zyjhtangtang in #2538
- Update README by @akhilmukkara in #2464
- Correct some inaccurate information by @zyjhtangtang in #2476
- Updated to CNCF Incubating Project by @zyjhtangtang in #2470
- Update the OpenYurt architecture diagram by @zyjhtangtang in #2485
- Update GVR for core.v1.services by @tnsimon in #2321
- yurt-manager chart support extraArgs by @william Wang in #2489
Fixes
- Always overwrite server-addr in yurt-static-set-yurt-hub configmap by yurtadm by @rayne-Li in #2271
- Test: fix nodepool e2e test by @tnsimon in #2283
- Fix openyurt fuzz test by @tnsimon in #2319
- Fix issue 2253 by @RG-Dou in #2330
- Ensure hub leader configmap is deleted with nodepool by @tnsimon in #2324
- Fix ota controller doesn't has permission to patch pod status by @PersistentJZH in #2415
- Fix: Fix the issue where the masterservice and serviceenvupdater modified the multiplexer cache by @zyjhtangtang in #2481
- Fix dummy-if name length exceeds 15 by @KubeKyrie in #2486
- Bugfix: remove deprecated rand.Seed() calls by @shiavm006 in #2499
- Fix: race condition in cache manager's inMemoryCache by @Shivam Mittal in #2508
- Fix: restore from backup and return error on ReplaceComponentList create/write failure by @Shivam Mittal in #2507
- Fix NodeAutonomy condition LastTransitionTime never being updated by @aman Kumar in #2502
- Fix: guard nil request info in autonomy proxy by @Shivam Mittal in #2517
- Fix: nil pointer dereference in local proxy (localDelete/localPost) by @Shivam Mittal in #2515
- Fix: avoid panic on pod without owner refs by @zyjhtangtang in #2509
- Fix: add unit test cases for modifyresponse by @kartik angiras in #2497
- Fix/UT error by @tnsimon in #2535
Proposals
v1.6.1
What's Changed
- [Backport release-v1.6] feat: improve yurthub configmap management by @github-actions in #2286
- [Backport release-v1.6] feat: remove yurt-coordinator from yurthub by @github-actions in #2287
- feat: upgrade k8s.io/xxx to v0.31.5 by @rambohe-ch in #2288
- [Backport release-v1.6] feat: improve readiness probe for yurthub component by @github-actions in #2289
- [Backport release-v1.6] feat: improve direct clientsets for yurthub by @github-actions in #2290
Full Changelog: v1.6.0...v1.6.1
v1.6.0
v1.6.0
What's New
Support Kubernetes up to V1.30
“k8s.io/xxx” and all its related dependencies are upgraded to version “v0.30.6”, for ensuring OpenYurt is compatible with Kubernetes v1.30 version. This compatibility has been confirmed by an end-to-end (E2E) test where we started a Kubernetes v1.30 cluster using KinD and deployed the latest components of OpenYurt.
#2179
#2249
Enhance edge autonomy capabilities
OpenYurt already offers robust edge autonomy capabilities, ensuring that applications on edge nodes can continue to operate even when the cloud-edge network is disconnected. However, there are several areas where the current edge autonomy capabilities can still be improved. For instance, once nodes are annotated with autonomy annotations, the cloud controller does not automatically evict Pods, regardless of whether the disconnection is due to cloud-edge network issues or node failures, yet users expect automatic Pod eviction during node failures. Additionally, the current edge autonomy capabilities cannot be directly used in managed Kubernetes environments because users cannot disable the NodeLifeCycle controller within the Kube-Controller-Manager component of managed Kubernetes. In this release, new endpoints/endpointslices webhooks are added to ensure that pods are not removed from the backend of the Service. Additionally, a new autonomous annotation is introduced, supporting the configuration of autonomous time.
#2155
#2201
#2211
#2218
#2241
Node-level Traffic Reuse Capability
In an OpenYurt cluster, control components are deployed in the cloud, and edge nodes usually interact with the cloud through the public internet, which can lead to significant consumption of cloud-edge traffic. This problem is more pronounced in large-scale clusters, mainly due to the edge-side components performing full-scale list/watch operations on resources. This not only consumes a large amount of cloud-edge traffic but also places considerable pressure on the apiserver due to the high volume of list operations. In this release, We have added a traffic multiplexing module in YurtHub. When multiple clients request the same resource (services, endpointslices), YurtHub returns data from the local cache, reducing the number of requests to the apiserver.
#2060
#2141
#2242
Other Notable changes
- Upgrade platformadmin's yurtappset dependencies to v1beta1 by @YTGhost in #2103
- Add yurthub service env updater filter by @techworldhello in #2165
- set transform to strip managedfields for informer by @vie-serendipity in #2149
- support cache response for partial object metadata requests。 by @rambohe-ch in #2170
- build iot system configuration isolation on nodepool by @WoShiZhangmingyu in #2147
- using the kubeconfig flag in controller-runtime. by @zyjhtangtang in #2193
- add events when no nodepool match with loadbalancerset services. by @zyjhtangtang in #2195
- Modify safety reporting Email by @zyjhtangtang in #2214
Fixes
- fix(iot): the mount type of hostpath for localtime in napa by @LavenderQAQ in #2110
- fix: create abspath dir in case that contents is empty by @vie-serendipity in #2164
- fix: masterservice missing clusterIPs field. by @fungaren in #2173
- fix: support cache response for partial object metedata watch request by @rambohe-ch in #2209
- fix: bug of yurtappset always the last tweaks make effect by @vie-serendipity in #2229
- fix: CRD WebhookConversion respect WEBHOOK_HOST env by @fungaren in #2217
- fix: go lint errors by @luc99hen in #2235
Proposals
- proposal: Node-level Traffic Reuse Capability by @zyjhtangtang in #2060
- Proposal: enhancing edge autonomy by @rambohe-ch in #2155
- proposal: enhance operational efficiency of K8s cluster in user's IDC by @huangchenzhao in #2124
- Proposal: build iot system configuration isolation on nodepool(#1597) by @WoShiZhangmingyu in #2135
Contributors
Thank you to everyone who contributed to this release! ❤
v1.5.1
What's Changed
- fix(iot): the mount type of hostpath for localtime in napa by @LavenderQAQ in #2111
- [Backport release-v1.5] fix: bug of yurtappset always the last tweaks make effect by @github-actions in #2243
Full Changelog: v1.5.0...v1.5.1
v1.5.0
v1.5.0
What's New
Support Kubernetes up to V1.28
“k8s.io/xxx” and all its related dependencies are upgraded to version “v0.28.9”, for ensuring OpenYurt is compatible with Kubernetes v1.28 version. This compatibility has been confirmed by an end-to-end (E2E) test where we started a Kubernetes v1.28 cluster using KinD and deployed the latest components of OpenYurt. At the same time, all the key components of OpenYurt, such as yurt-manager and yurthub, are deployed on the Kubernetes cluster via Helm to ensure that the Helm charts provided by the OpenYurt community can run stably in the production environment.
#2047
#2074
Reduce cloud-edge traffic spike during rapid node additions
NodePool resource is essential for managing groups of nodes within OpenYurt clusters, as it records details of all nodes in the collective through the NodePool.status.nodes field. YurtHub relies on this information to identify endpoints within the same NodePool, thereby enabling pool-level service topology functionality. However, when a large NodePool—potentially comprising thousands of nodes—experiences swift expansion, such as the integration of hundreds of edge nodes within a mere minute, the surge in cloud-to-edge network traffic can be significant. In this release, a new type of resource called NodeBucket has been introduced. It provides a scalable and streamlined method for managing extensive NodePool, significantly reducing the impact on cloud-edge traffic during periods of rapid node growth, and ensuring the stability of the clusters is maintained.
#1864
#1874
#1930
Upgrade YurtAppSet to v1beta1 version
YurtAppSet v1beta1 is introduced to facilitate the management of multi-region workloads. Users can use YurtAppSet to distribute the same WorkloadTemplate (Deployment/Statefulset) to different nodepools by a label selector NodePoolSelector or nodepool name slice (Pools). Users can also customize the configuration of workloads in different node pools through WorkloadTweaks.
In this release, we have combined the functionality from the three old crds (YurtAppSet v1alpha1, YurtAppDaemon and YurtAppOverrider) in yurtappset v1beta1. We recommend to use this in favor of the old ones.
#1890
#1931
#1939
#1974
#1997
Improve transparent management mechanism for control traffic from edge to cloud
The current transparent management mechanism for cloud-edge control traffic has certain limitations and cannot effectively support direct requests to the default/kubernetes service. In this release, a new transparent management mechanism for cloud-edge control traffic, aimed at enabling pods using InClusterConfig or the default/kubernetes service name to access the kube-apiserver via YurtHub without needing to be aware of the details of the public network connection between the cloud and edge.
#1975
#1996
Separate clients for yurt-manager component
Yurt-manager is an important component in cloud environment for OpenYurt which holds multiple controllers and webhooks. Those controllers and webhooks shared one client and one set of RBAC (yurt-manager-role/yurt-manager-role-binding/yurt-manager-sa) which grew bigger as we add more function into yurt-manager. This mechanism makes a controller has access it shouldn't has. and it's difficult to find out the request is from which controller from the audit logs. In the latest release, we restrict each controller/webhook to only the permissions it may use and separate RBAC and UA for different controllers and webhooks.
#2051
#2069
Enhancement to Yurthub's Autonomy capabilities
New autonomy condition have been added to node conditions so that yurthub can report autonomy status of node in real time at each nodeStatusUpdateFrequency. This condition allows for accurate determination of each node's autonomy status. In addition, an error key mechanism has been introduced to log cache failure keys along with their corresponding fault reasons. The error keys are persisted using the AOF (Append-Only File) method, ensuring that the autonomy state is recovered even after a reboot and preventing the system from entering a pseudo-autonomous state. These enhancements also facilitate easier troubleshooting when autonomy issues arise.
#2015
#2033
#2096
Other Notable changes
- improve ca data for yurthub component by @rambohe-ch in #1815
- improve FieldIndexer setting in yurt-manager by @2456868764 in #1834
- fix: yurtadm join ignorePreflightErrors could not set all by @YTGhost in #1837
- Feature: add name-length of dummy interface too long error by @8rxn in #1875
- feat: support v3 rest api client for edgex v3 api by @wangxye in #1850
- feat: support edgex napa version by auto-collector by @LavenderQAQ in #1852
- feat: improve discardcloudservice filter in yurthub component (#1924) by @huangchenzhao in #1926
- Add missing verb to the role of node lifecycle controller by @crazytaxii in #1936
- don't cache csr and sar resource in yurthub by @rambohe-ch in #1949
- feat: improve hostNetwork mode of NodePool by adding NodeAffinity to pods with specified annotation (#1935) by @huangchenzhao in #1959
- move list object handling from ObjectFilter into ResponseFilter by @rambohe-ch in #1991
- The gateway can forward traffic from extra source cidrs by @River-sh in #1993
- return back watch.Deleted event to clients when watch object is removed in OjbectFilters by @rambohe-ch in #1995
- add pool service controller. by @zyjhtangtang in #2010
- aggregated annotations and labels. by @zyjhtangtang in #2027
- improve pod webhook for adapting hostnetwork mode nodepool by @rambohe-ch in #2050
- intercept kubelet get node request in order to reduce the traffic by @vie-serendipity in #2039
- bump controller-gen to v0.13.0 by @Congrool in #2056
- improve nodepool conversion by @rambohe-ch in #2080
- feat: add version metrics for yurt-manager and yurthub components by @rambohe-ch in #2094
Fixes
- fix cache manager panic in yurthub by @rambohe-ch in #1950
- fix: upgrade the version of runc to avoid security risk by @qclc in #1972
- fix only openyurt crd conversion should be handled for upgrading cert by @rambohe-ch in #2013
- fix the cache leak in yurtappoverrider controller by @MeenuyD in #1795
- fix(yurt-manager): add clusterrole for nodes/status subresources by @qclc in #1884
- fix: close dst file by @testwill in #2046
Proposals
- Proposal: High Availability of Edge Services by @Rui-Gan in #1816
- Proposal: yurt express: openyurt data transmission system proposal by @qsfang in #1840
- proposal: add NodeBucket to reduce cloud-edge traffic spike during rapid node additions. by @rambohe-ch in #1864
- Proposal: add yurtappset v1beta1 proposal by @luc99hen in #1890
- proposal: improve transparent management mechanism for control traffic from edge to cloud by @rambohe-ch in #1975
- Proposal: enhancement of edge autonomy by @vie-serendipity in #2015
- Proposal: separate yurt-manager clients by @luc99hen in #2051
Contributors
Thank you to everyone who contributed to this release! ❤
v1.4.4
What's Changed
- fix: edgex component creation cause registration errors and core-command crash by @LavenderQAQ in #2030
Full Changelog: v1.4.3...v1.4.4
v1.4.3
What's Changed
- [Backport release-v1.4] fix only openyurt crd conversion should be handled for upgrading cert by @github-actions in #2014
Full Changelog: v1.4.2...v1.4.3
v1.4.2
What's Changed
- [Backport release-v1.4] fix: yurtadm join can't work when kubernetes version large than v1.27.0 by @github-actions in #1998
Full Changelog: v1.4.1...v1.4.2
v1.4.1
What's Changed
- [Backport release-v1.4] fix cache manager panic in yurthub by @github-actions in #1951
- [Backport release-v1.4] fix: yurtadm join ignorePreflightErrors could not set all by @github-actions in #1954
- [Backport release-v1.4] Feature: add name-length of dummy interface too long error by @github-actions in #1952
- [Backport release-v1.4] feat: bookmark and error response should be skipped in yurthub filter (#1868) by @github-actions in #1953
Full Changelog: v1.4.0...v1.4.1
v1.4.0
v1.4.0
What's New
Support for HostNetwork Mode NodePool
When the resources of edge nodes are limited and only simple applications need to be run (for instance, situations where container network is not needed and there is no need for communication between applications),
using a HostNetwork mode nodepool is a reasonable choice. When creating a nodepool, users only need to set spec.HostNetwork=true to create a HostNetwork mode nodepool.
In this mode, only some essential components such as kubelet, yurthub and raven-agent will be installed on all nodes in the pool. In addition, Pods scheduled on these nodes will automatically adopt host network mode.
This method effectively reduces resource consumption while maintaining application performance efficiency.
Support for customized configuration at the nodepool level for multi-region workloads
YurtAppOverrider is a new CRD used to customize the configuration of the workloads managed by YurtAppSet/YurtAppDaemon. It provides a simple and straightforward way to configure every field of the workload under each nodepool.
It is fundamental component of multi-region workloads configuration rendering engine.
Support for building edgex iot systems by using PlatformAdmin
PlatformAdmin is a CRD that manages the IoT systems in the OpenYurt nodepool. It has evolved from the previous yurt-edgex-manager. Starting from this version, the functionality of yurt-edgex-controller has been merged into yurt-manager. This means that users no longer need to deploy any additional components; they only need to install yurt-manager to have all the capabilities for managing edge devices.
PlatformAdmin allows users with a user-friendly way to deploy a complete edgex system on nodepool. It comes with an optional component library and configuration templates. Advanced users can also customize the configuration of this system according to their needs.
Currently, PlatformAdmin supports all versions of EdgeX from Hanoi to Minnesota. In the future, it will continue to rapidly support upcoming releases using the auto-collector feature. This ensures that PlatformAdmin remains compatible with the latest versions of EdgeX as they are released.
Supports yurt-iot-dock deployment as an iot system component
yurt-iot-dock is a component responsible for managing edge devices in IoT system. It has evolved from the previous yurt-device-controller. As a component that connects the cloud and edge device management platforms, yurt-iot-dock abstracts three CRDs: DeviceProfile, DeviceService, and Device. These CRDs are used to represent and manage corresponding resources on the device management platform, thereby impacting real-world devices.
By declaratively modifying the fields of these CRs, users can achieve the operational and management goals of complex edge devices in a cloud-native manner. yurt-iot-dock is deployed by PlatformAdmin as an optional IoT component. It is responsible for device synchronization during startup and severs the synchronization relationship when being terminated or destroyed.
In this version, the deployment and destruction of the yurt-iot-dock are all controlled by PlatformAdmin, which improves the ease of use of the yurt-iot-dock.
Some Repos are archived
With the upgrading of OpenYurt architecture, the functions of quite a few components are merged into Yurt-Manager (e.g. yurt-app-manager, raven-controller-manager, etc.),
or there are repos migrated to openyurt for better management (e.g. yurtiotdock). The following repos have been archived:
- yurt-app-manager
- yurt-app-manager-api
- raven-controller-manager
- yurt-edgex-manager
- yurt-device-controller
- yurtcluster-operator
Other Notable changes
- feat: use real kubernetes server address to yurthub when yurtadm join by @Lan-ce-lot in #1517
- yurtadm support enable kubelet service by @YTGhost in #1523
- feat: support SIGUSR1 signal for yurthub by @y-ykcir in #1487
- feat: remove yurtadm init command by @YTGhost in #1537
- add yurtadm join node in specified nodepool by @JameKeal in #1402
- rename pool-coordinator to yurt-coordinator for charts by @JameKeal in #1551
- move iot controller to yurt-manager by @Rui-Gan in #1488
- feat: provide config option for yurtadm by @YTGhost in #1547
- add yurtadm to install/uninstall staticpod by @JameKeal in #1550
- change access permission to default in general. by @fujitatomoya in #1576
- build: added github registry by @siredmar in #1578
- feat: support edgex minnesota through auto-collector by @LavenderQAQ in #1582
- feat: prevent node movement by label modification by @y-ykcir in #1444
- add cpu limit for yurthub by @huweihuang in #1609
- feat: provide users with the ability to customize the edgex framework by @LavenderQAQ in #1596
- add kubelet certificate mode in yurthub by @rambohe-ch in #1625
- delete configmap when yurtstaticset is deleting by @JameKeal in #1640
- add new gateway version v1beta1 by @River-sh in #1641
- feat: reclaim device, deviceprofile and deviceservice before exiting YurtIoTDock by @wangxye in #1647
- feat: upgrade YurtIoTDock to support edgex v3 api by @wangxye in #1666
- feat: add token format checking to yurtadm join process by @YTGhost in #1681
- Add status info to YurtAppSet/YurtAppDaemon by @vie-serendipity in #1702
- fix(yurt-manager): raven controller can't list calico blockaffinity by @luckymrwang in #1676
- feat: support yurtadm config command by @YTGhost in #1709
- improve lease lock for yurt-manager component by @rambohe-ch in #1741
- add nodelifecycle controller by @rambohe-ch in #1746
- disable the iptables setting of yurthub component by default by @rambohe-ch in #1770
Fixes
- fix memory leak for yur-tunnel-server by @huweihuang in #1471
- fix yurthub memory leak by @JameKeal in #1501
- fix yurtstaticset workerpod reset error by @JameKeal in #1526
- fix conflicts for getting node by local storage in yurthub filters by @rambohe-ch in #1552
- fix work dir nested
yurthub/yurthubby @luc99hen in #1693 - fix pool scope crd resource etcd key path by @qsfang in #1729
Proposals
- proposal for raven l7 by @River-sh in #1541
- proposal of support raven NAT traversal by @YTGhost in #1639
- Proposal for Multi-region workloads configuration rendering engine by @vie-serendipity in #1600
- Proposal of install openyurt components using dashboard by @401lrx in #1664
- Proposal use message-bus instead of REST to communicate with EdgeX by @Pluviophile225 in #1680
Contributors
Thank you to everyone who contributed to this release! ❤
- @huiwq1990
- @y-ykcir
- @JameKeal
- @Lan-ce-lot
- @YTGhost
- @fujitatomoya
- @LavenderQAQ
- @River-sh
- @huweihuang
- @luc99hen
- @luckymrwang
- @wangzihao05
- @yojay11717
- @lishaokai1995
- @yeqiugt
- @TonyZZhang
- @vie-serendipity
- @my0sotis
- @Rui-Gan
- @zhy76
- @siredmar
- @wangxye
- @401lrx
- @testwill
- @Pluviophile225
- @shizuocheng
- @qsfang
And thank you very much to everyone else not listed here who contributed in other ways like filing issues,
giving feedback, ...