1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-26 05:14:13 +01:00

Compare commits

...

336 Commits

Author SHA1 Message Date
a7i
782058a67c Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2025-10-30 16:41:34 +00:00
a7i
6ecff2d544 Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2025-05-04 19:49:46 +00:00
k8s-ci-robot
241e3c50f7 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2025-02-11 04:46:21 +00:00
k8s-ci-robot
345e1f7139 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2025-01-06 23:08:49 +00:00
a7i
818033a143 Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2025-01-02 23:34:03 +00:00
k8s-ci-robot
54540412b8 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2024-11-20 15:09:49 +00:00
a7i
e91082a4e9 Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2024-09-09 22:59:21 +00:00
k8s-ci-robot
74150670ed Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2024-06-05 12:06:23 +00:00
a7i
8662aa75b1 Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2024-05-20 14:03:13 +00:00
a7i
25876a2d2d Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2024-01-02 18:54:21 +00:00
k8s-ci-robot
28a3011f77 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2023-11-29 17:22:04 +00:00
a7i
751a0dec8e Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2023-08-24 13:07:51 +00:00
k8s-ci-robot
932bf0bb42 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2023-05-31 08:18:14 +00:00
a7i
da42d43c2f Update index.yaml
Signed-off-by: a7i <a7i@users.noreply.github.com>
2023-05-05 14:14:44 +00:00
k8s-ci-robot
39066a41de Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2023-04-04 17:34:17 +00:00
damemi
640d4af538 Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2023-01-17 14:42:00 +00:00
k8s-ci-robot
fe135ef841 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2022-10-17 21:53:53 +00:00
k8s-ci-robot
df30be9f04 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2022-09-27 15:02:20 +00:00
damemi
6dcb094ada Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2022-09-15 16:33:37 +00:00
k8s-ci-robot
8849b415fa Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2022-05-31 13:39:20 +00:00
damemi
3d6c3c82ae Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2022-05-23 14:14:10 +00:00
k8s-ci-robot
245b8c0f84 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2022-02-28 18:56:10 +00:00
k8s-ci-robot
f6ef3370cd Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2022-02-09 13:34:50 +00:00
k8s-ci-robot
6bdefcbeff Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2022-02-03 20:23:32 +00:00
k8s-ci-robot
9f3411a93e Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2021-09-29 16:37:16 +00:00
k8s-ci-robot
6f8585493e Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2021-09-08 20:44:21 +00:00
damemi
2213cb977c Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2021-06-08 17:43:48 +00:00
damemi
bf052b2fed Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2020-12-10 15:23:17 +00:00
Kubernetes Prow Robot
e372b00b9a Merge pull request #460 from damemi/empty-gh-pages
Delete everything but index.yaml from gh-pages
2020-12-09 06:40:50 -08:00
Mike Dame
1795479cf0 Delete everything but index.yaml from gh-pages 2020-12-08 20:53:05 -05:00
damemi
97a0ab922f Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2020-12-09 01:47:49 +00:00
k8s-ci-robot
81df2c3da8 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2020-12-08 19:34:03 +00:00
k8s-ci-robot
9e35349cb3 Update index.yaml
Signed-off-by: k8s-ci-robot <k8s-ci-robot@users.noreply.github.com>
2020-12-08 19:22:08 +00:00
damemi
6e1f88b932 Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2020-09-01 16:59:23 +00:00
damemi
a14d4bfba2 Update index.yaml
Signed-off-by: damemi <damemi@users.noreply.github.com>
2020-07-23 18:29:33 +00:00
Kubernetes Prow Robot
0894f7740c Merge pull request #343 from ingvagabund/test-cleanup
Clean e2e test so it's easier to extend it
2020-07-21 05:21:13 -07:00
Kubernetes Prow Robot
c3f07dc366 Merge pull request #351 from KohlsTechnology/helm-release-docs
Update Release Documentation For Helm Charts
2020-07-20 20:33:14 -07:00
Sean Malloy
ca8f1051eb Update Helm Chart Version To 0.18.0 2020-07-20 12:52:38 -05:00
Sean Malloy
c7692a2e9f Update Release Documentation For Helm Charts
The descheduler now has an official helm chart. This change documents the
process to release a new helm chart artifact.
2020-07-20 12:51:50 -05:00
Jan Chaloupka
53badf7b61 e2e: create dedicated ns for each e2e test 2020-07-17 18:15:53 +02:00
Jan Chaloupka
f801c5f72f e2e: code cleanup 2020-07-17 18:15:13 +02:00
Jan Chaloupka
327880ba51 e2e: separate tests for LowNodeUtilization strategy and evict annotation 2020-07-17 18:11:01 +02:00
Jan Chaloupka
7bb8b4feda e2e: create and delete RC in the same function body
So create/delete are coupled and caller of create is responsible for calling delete as well
2020-07-17 18:06:19 +02:00
Kubernetes Prow Robot
36b1e1f061 Merge pull request #298 from stevehipwell/helm-chart
Add Helm chart
2020-07-16 16:15:00 -07:00
Steve Hipwell
4507a90bb6 Add helm chart 2020-07-16 17:36:17 +01:00
Kubernetes Prow Robot
550f68306c Merge pull request #342 from KohlsTechnology/remove-travis-ci-config
Remove Travis CI Configuration
2020-07-16 07:05:41 -07:00
Sean Malloy
2b668566ce Remove Travis CI Configuration
The e2e tests are now being run through Prow. Therefore the Travis CI
configuration can now be completely removed.
2020-07-15 23:52:27 -05:00
Kubernetes Prow Robot
ee414ea366 Merge pull request #344 from ingvagabund/kind-have-version-configurable-through-env
e2e: have k8s version configurable when creating cluster through kind
2020-07-14 06:47:21 -07:00
Jan Chaloupka
5761b5d595 e2e: have k8s version configurable when creating cluster through kind 2020-07-14 15:25:02 +02:00
Kubernetes Prow Robot
07f476dfc4 Merge pull request #340 from damemi/update-e2e
Update e2e script to use Kind setup
2020-07-13 19:57:20 -07:00
Mike Dame
f5e9f07321 Move kind setup to e2e script
This moves the kind setup (previously used by Travis) to the e2e runner script
to accomodate the switch to Prow. This provides a KIND_E2E env var to specify
whether to run the tests in kind, or (by default) to run locally).
2020-07-13 15:49:41 -04:00
Kubernetes Prow Robot
05c69ee26a Merge pull request #336 from lixiang233/avoid_duplicated_append_RemoveDuplicatePods
avoid appending list multiple times in RemoveDuplicates
2020-07-09 01:32:02 -07:00
Kubernetes Prow Robot
1623e09122 Merge pull request #332 from lixiang233/fix_test_struct_lownodeutilization
Add maxPodsToEvictPerNode to LowNodeUtilization testcase struct
2020-07-09 01:22:02 -07:00
lixiang
696aa7c505 rename maxPodsToEvict to maxPodsToEvictPerNode to avoid misunderstanding 2020-07-08 15:15:48 +08:00
lixiang
c53dce0805 Add maxPodsToEvictPerNode to testcase struct 2020-07-08 15:15:38 +08:00
lixiang
cd8b5a0354 avoid appending list multiple times in RemoveDuplicates 2020-07-07 14:42:53 +08:00
Kubernetes Prow Robot
b51f24eb8e Merge pull request #333 from lixiang233/refactor_lowNodeUtilization_func
Support only one sorting strategy in lowNodeUtilization
2020-07-02 22:48:47 -07:00
lixiang
ae3b4368ee support only one sorting strategy in lowNodeUtilization 2020-07-01 09:47:35 +08:00
Kubernetes Prow Robot
61eef93618 Merge pull request #330 from paulfantom/patch-1
examples: fix typo
2020-06-29 07:27:24 -07:00
Paweł Krupa
fa0a2ec6fe examples: fix typo
Fix incorrect example causing following error in runtime:

PodsHavingTooManyRestarts thresholds not set
2020-06-28 14:28:41 +02:00
Kubernetes Prow Robot
7ece10a643 Merge pull request #328 from KohlsTechnology/go114
Update To Go 1.14.4
2020-06-25 08:26:39 -07:00
Sean Malloy
71c8eae47e Update To Go 1.14.4
The kubernetes project has been updated to use Go 1.14.4. See below pull
request.

https://github.com/kubernetes/kubernetes/pull/88638

After making the updates to Go 1.14 "make gen" no longer worked. The
file hack/tools.go had to be created to get "make gen" working with Go
1.14.
2020-06-23 21:33:28 -05:00
Kubernetes Prow Robot
267b0837dc Merge pull request #327 from farah/farah/klog-migration
Update klog to v2
2020-06-23 08:35:40 -07:00
Kubernetes Prow Robot
c713537d56 Merge pull request #322 from lixiang233/move_pod_sort
Move sortPodsBasedOnPriority to pod util
2020-06-22 12:21:40 -07:00
Kubernetes Prow Robot
e374229707 Merge pull request #325 from KohlsTechnology/issue-template
Add initial GitHub issue templates
2020-06-22 07:42:40 -07:00
Sean Malloy
f834581a8e Fix Spelling Error 2020-06-22 09:12:22 -05:00
Ali Farah
15fcde5229 Update klog to v2 2020-06-22 20:43:22 +10:00
Sean Malloy
96c5dd3941 Add initial GitHub issue templates
Initially users can open a bug report, feature request, or misc request.
Bug reports and feature requests will have the "kind" label
automatically added.
2020-06-20 00:52:23 -05:00
lixiang
65a03e76bf Add sorting to RemovePodsViolatingInterPodAntiAffinity 2020-06-19 14:11:23 +08:00
lixiang
43525f6493 Move sortPodsBasedOnPriority to podutil 2020-06-16 19:19:03 +08:00
lixiang
7457626f62 Move helper funcs to testutil 2020-06-16 19:17:28 +08:00
Kubernetes Prow Robot
08c22e8921 Merge pull request #321 from KohlsTechnology/add-event-reason
Add Pod Eviction Reason To Events
2020-06-15 08:53:57 -07:00
Sean Malloy
4ff533ec17 Add pod eviction reason to k8s events
Prior to this change the event created for every pod eviction was
identical. Instead leverage the newly added eviction reason when
creating k8s events. This makes it easier for end users to understand
why the descheduler evicted a pod when inspecting k8s events.
2020-06-10 01:13:17 -05:00
Sean Malloy
7680e3d079 Use var declaration instead of short assignmnet
This is a very minor refactor to use a var declaration for the reason
variable. A var declaration is being used because the zero value for
strings is an empty string.

https://golang.org/ref/spec#The_zero_value
2020-06-10 01:05:05 -05:00
Kubernetes Prow Robot
305801dd0e Merge pull request #319 from damemi/remove-extra-eviction-log
Remove redundant eviction log message and add "Reason" param to EvictPod
2020-06-09 11:25:19 -07:00
Mike Dame
9951b85d60 Add optional reason parameter to EvictPod 2020-06-09 13:35:51 -04:00
Mike Dame
ff21ec9432 Remove redundant eviction log message 2020-06-09 12:17:45 -04:00
Kubernetes Prow Robot
5e15d77bf2 Merge pull request #309 from damemi/change-evict-local-storage-pods
Make evictLocalStoragePods a property of PodEvictor
2020-06-08 03:53:46 -07:00
Kubernetes Prow Robot
d833c73fc4 Merge pull request #317 from ingvagabund/extend-owners
Add myself to project reviewers
2020-06-05 10:45:44 -07:00
Kubernetes Prow Robot
795a80dfb0 Merge pull request #310 from lixiang233/ignore_no_evictable_pod_node
Skip evicting when no evictable pod found on node
2020-06-05 07:41:44 -07:00
Mike Dame
f5e4acdd8a Make evictLocalStoragePods a property of PodEvictor
This is a minor refactor of PodEvictor to include evictLocalStoragePods as a
property (so that it doesn't need to be passed to each strategy function.) It
also removes ListEvictablePodsOnNode and extends ListPodsOnANode with an optional
"filter" function parameter, so that for example IsEvictable can be passed to it
and achieve the same results as the function formerly known as ListEvictablePodsOnNode.
This approach also now allows strategies to more explicitly extend their criteria of what
IsEvictable considers an evictable pod (such as NodeAffinity, which checks that the pod
can fit on any other node).
2020-06-05 10:28:48 -04:00
Jan Chaloupka
eb4c1bb355 Add myself to project reviewers
Based on https://github.com/kubernetes/community/blob/master/community-membership.md#requirements-1:

The following apply to the part of codebase for which one would be a reviewer in an OWNERS file (for repos using the bot).

> member for at least 3 months

For a couple of years now

> Primary reviewer for at least 5 PRs to the codebase

https://github.com/kubernetes-sigs/descheduler/pull/285
https://github.com/kubernetes-sigs/descheduler/pull/275
https://github.com/kubernetes-sigs/descheduler/pull/267
https://github.com/kubernetes-sigs/descheduler/pull/254
https://github.com/kubernetes-sigs/descheduler/pull/181

> Reviewed or merged at least 20 substantial PRs to the codebase

https://github.com/kubernetes-sigs/descheduler/pulls?q=is%3Apr+is%3Aclosed+assignee%3Aingvagabund

> Knowledgeable about the codebase

yes

> Sponsored by a subproject approver
> With no objections from other approvers
> Done through PR to update the OWNERS file

this PR

> May either self-nominate, be nominated by an approver in this subproject, or be nominated by a robot

self-nominating
2020-06-04 18:16:38 +02:00
Kubernetes Prow Robot
6dfa95cc87 Merge pull request #312 from lixiang233/fix_lowUtilization_golint
Pass golint check for pkg/descheduler/strategies/
2020-06-04 07:09:15 -07:00
lixiang
eb9d974a8b pass golint check for pkg/descheduler/strategies/ 2020-06-04 14:33:24 +08:00
lixiang
d41a1f4a56 Ignore evicting when no evictable pod found on node 2020-06-04 10:31:15 +08:00
Kubernetes Prow Robot
138ad556a3 Merge pull request #315 from damemi/update-travis-yml
Remove redundant tests from Travis CI
2020-06-03 11:44:11 -07:00
Mike Dame
37124e6e45 Remove redundant tests from Travis CI
These tests are now covered by k8s test-infra prow tests.
2020-06-03 14:11:08 -04:00
Kubernetes Prow Robot
bd412bf87f Merge pull request #300 from damemi/refactor-is-evictable
Add more verbose logging to IsEvictable checks
2020-05-29 10:03:16 -07:00
Kubernetes Prow Robot
6f9b31f568 Merge pull request #308 from damemi/fix-lint-for-ci
Download golangci-lint to _output/bin directory
2020-05-29 09:57:15 -07:00
Mike Dame
c858740c4f Run golangci-lint from GOPATH 2020-05-29 12:48:42 -04:00
Kubernetes Prow Robot
bfefe634a1 Merge pull request #307 from damemi/make-verify
Add parent make verify target
2020-05-29 08:01:16 -07:00
Mike Dame
7b7b9e1cd7 Add parent make verify target 2020-05-29 10:23:38 -04:00
Mike Dame
0a4b8b0a25 Add more verbose logging to IsEvictable checks 2020-05-29 10:20:14 -04:00
Kubernetes Prow Robot
f28183dcbe Merge pull request #306 from ingvagabund/make-Params-a-pointer-II
Add missing address of api.StrategyParameters
2020-05-29 05:53:16 -07:00
Jan Chaloupka
abdf79454f Add missing address of api.StrategyParameters
https://github.com/kubernetes-sigs/descheduler/pull/285 got merged before re-running the unit tests.
2020-05-29 13:34:57 +02:00
Kubernetes Prow Robot
46b570b71d Merge pull request #296 from ingvagabund/make-Params-a-pointer
Make DeschedulerStrategy.Params a pointer
2020-05-28 22:53:15 -07:00
Kubernetes Prow Robot
616a9b5f6b Merge pull request #285 from lixiang233/Ft_change_lowUtilization_break
Change break condition and thresholds validation for lowUtilization
2020-05-28 07:36:02 -07:00
Kubernetes Prow Robot
003a4cdc2b Merge pull request #302 from lixiang233/clean_up_strategy_enable_check
Clean up code in LowNodeUtilization
2020-05-28 07:16:02 -07:00
Kubernetes Prow Robot
54ea05d8bb Merge pull request #299 from damemi/node-affinity-logs
Standardize node affinity strategy logs
2020-05-28 01:52:02 -07:00
lixiang
d0eea0cabb Clean up code in LowNodeUtilization 2020-05-28 10:35:46 +08:00
Mike Dame
f0297dfe03 Standardize node affinity strategy logs 2020-05-27 16:52:16 -04:00
Kubernetes Prow Robot
ef1f36f8e4 Merge pull request #297 from ingvagabund/add-verify-gofmt
Add verify-gofmt make target
2020-05-27 07:02:40 -07:00
Jan Chaloupka
a733c95dcc Add verify-gofmt and verify-vendor make target
So e.g. CI can run 'make verify-gofmt' instead of ./hack/verify-gofmt in case the script location changes.
2020-05-27 15:08:20 +02:00
Jan Chaloupka
5a81a0661b Make DeschedulerStrategy.Params a pointer
To avoid empty params fields when serializing:
  RemoveDuplicates:
    enabled: true
    params: {}
  RemovePodsHavingTooManyRestarts:
    enabled: true
    params:
      podsHavingTooManyRestarts: {}
  RemovePodsViolatingInterPodAntiAffinity:
    enabled: true
    params: {}
  RemovePodsViolatingNodeAffinity:
    enabled: true
    params:
      nodeAffinityType:
      - requiredDuringSchedulingIgnoredDuringExecution
  RemovePodsViolatingNodeTaints:
    enabled: true
    params: {}
2020-05-27 10:31:31 +02:00
Kubernetes Prow Robot
83e04960af Merge pull request #288 from KohlsTechnology/update-support-matrix
Update Compatibility Matrix in README
2020-05-26 06:37:12 -07:00
lixiang
2a8dc69cbb Stop condition and config validation change for lowUtilization
1.Set default CPU/Mem/Pods percentage of thresholds to 100
2.Stop evicting pods if any resource ran out
3.Add thresholds verification method and limit resource percentage within [0, 100]
4.Change testcases and readme
2020-05-25 19:03:37 +08:00
Kubernetes Prow Robot
5d82d08af3 Merge pull request #291 from KohlsTechnology/update-releasedocs
Add URL For Viewing Staging Registry
2020-05-22 09:55:11 -07:00
Sean Malloy
c265825166 Add URL For Viewing Staging Registry
This newly documented URL can be used to view the descheduler staging
registry in a web browser. This is easier to browse if the gcloud
command is not available.
2020-05-22 11:33:45 -05:00
Kubernetes Prow Robot
ed0126fb63 Merge pull request #290 from KohlsTechnology/bump-install-manifests
Update Install Manifests For Release v0.18.0
2020-05-22 07:08:38 -07:00
Sean Malloy
8c7267b379 Update Install Manifests For Release v0.18.0 2020-05-21 22:54:54 -05:00
Kubernetes Prow Robot
d85ce22975 Merge pull request #289 from KohlsTechnology/update-release-docs
Update Release Guide
2020-05-20 11:46:19 -07:00
Kubernetes Prow Robot
a9091a1e37 Merge pull request #287 from ingvagabund/evict-pod-mention-dry-run-if-set
Mention pod eviction is in dry mode when set
2020-05-20 11:44:19 -07:00
Sean Malloy
d3b0ac8e06 Update Release Guide
Starting with descheduler v0.18 a release branch will be created for
each descheduler minor release. The release guide has been updated with
the steps to create release branches.
2020-05-20 11:10:42 -05:00
Sean Malloy
435674fb44 Update Compatibility Matrix in README
The matrix has been updated with the soon the be released v0.18
details. Also, clarified the descheduler and k8s version compatibility
requirements and recommendations.
2020-05-20 10:55:57 -05:00
Jan Chaloupka
eacbae72fd Mention pod eviction is in dry mode when set
Indicate whether a pod is only virtually evicted so there's no confusion
with the real eviction.
2020-05-20 10:40:58 +02:00
Kubernetes Prow Robot
34550d4b7c Merge pull request #275 from damemi/image-in-duplicates
Consider pod image in duplicates strategy
2020-05-15 06:51:38 -07:00
Mike Dame
c6ff87dbd6 Consider pod image in duplicates strategy
This increases the specificity of the RemoveDuplicates strategy by
removing pods which not only have the same owner, but who also
must have the same list of container images. This also adds a
parameter, `ExcludeOwnerKinds` to the RemoveDuplicates strategy
which accepts a list of Kinds. If a pod has any of these Kinds as
an owner, that pod is not considered for eviction.
2020-05-15 09:37:09 -04:00
Kubernetes Prow Robot
04efe65f90 Merge pull request #279 from KohlsTechnology/eviction-logs
Add Additional Details To Pod Eviction Log Messages
2020-05-14 07:20:22 -07:00
Sean Malloy
55afde6251 Remove line break in log message from PodLifeTime strategy 2020-05-14 00:36:52 -05:00
Sean Malloy
7039b6c8aa Refactor function EvictPod to only return an error
The EvictPod function previously returned a bool and an error. The
function now only returns an error. Callers can check for failure by
testing if the returned error is not nil. This aligns the EvictPod
function with idiomatic Go best practices.

Also, the function name has been changed from EvictPod to evictPod
because it is not used outside the evictions package.
2020-05-14 00:11:54 -05:00
Sean Malloy
cff984261e Log an error when EvictPod method returns a non-nil error
End users should be able to see the detailed error from the EvictPod
method when it fails. Updates all strategies to log the error. The
PodLifeTime strategy already logs this error.
2020-05-13 23:36:32 -05:00
Sean Malloy
4819ab9c69 Add namespace to pod eviction log messages
In multi-tenant environments it is useful to know which namespace a pod
was evicted from. Therefore log the namespace when evicting pods.

Also, do not log a nil error when successfully evicting pods.
2020-05-13 23:28:25 -05:00
Kubernetes Prow Robot
25336da708 Merge pull request #281 from KohlsTechnology/update-travis-ci
Update Travis CI build matrix with latest k8s point releases
2020-05-13 08:20:26 -07:00
Sean Malloy
4941f6a16b Update Travis CI build matrix with latest k8s point releases 2020-05-12 22:38:23 -05:00
Kubernetes Prow Robot
d7e93058d4 Merge pull request #280 from damemi/k8s-1.18
Update to k8s 1.18.2 dependencies
2020-05-12 13:40:21 -07:00
Mike Dame
c20a595370 Update travis.yml with new k8s version and updated kind version 2020-05-12 15:01:25 -04:00
Mike Dame
eec1104d6e React to 1.18 by adding contexts to client calls 2020-05-12 15:01:25 -04:00
Mike Dame
741b35edf5 Update to k8s 1.18.2 dependencies 2020-05-12 14:07:31 -04:00
Kubernetes Prow Robot
c01cfcf3b6 Merge pull request #274 from KohlsTechnology/pod-lifetime-strategy
Add New PodLifeTime Strategy
2020-05-08 07:29:42 -07:00
Sean Malloy
643cd472ef Add initial production use cases section to user guide 2020-05-08 09:02:24 -05:00
Sean Malloy
668d727fc2 Add VS Code File To .gitignore 2020-05-07 23:10:48 -05:00
Sean Malloy
423ee35846 Add New PodLifeTime Strategy
The new PodLifeTime descheduler strategy can be used to evict pods that
were created more than the configured number of seconds ago.

In the below example pods created more than 24 hours ago will be evicted.
````
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
  "PodLifeTime":
     enabled: true
     params:
        maxPodLifeTimeSeconds: 86400
````
2020-05-07 23:10:36 -05:00
Kubernetes Prow Robot
31c7855212 Merge pull request #278 from lixiang233/fix_readme
Fix readme
2020-05-07 12:19:43 -07:00
Kubernetes Prow Robot
211f3942b6 Merge pull request #276 from damemi/toomanyrestarts-pointer
Switch PodsHavingTooManyRestarts params to pointer
2020-05-07 12:17:42 -07:00
Kubernetes Prow Robot
beae282735 Merge pull request #277 from damemi/damemi-approvers
Add damemi to approvers
2020-05-07 12:15:42 -07:00
lixiang
635348efb9 Fix readme 2020-05-07 11:47:32 +08:00
Mike Dame
fa335c782f Switch PodsHavingTooManyRestarts params to pointer 2020-05-06 13:29:05 -04:00
Mike Dame
b019a58525 Add damemi to approvers 2020-05-06 11:00:58 -04:00
Kubernetes Prow Robot
78eef6c343 Merge pull request #267 from ingvagabund/drop-DeschedulerServer-from-strategies
Drop descheduler server from strategies
2020-04-28 08:34:06 -07:00
Jan Chaloupka
cbcefb5d2f Remove options.DeschedulerServer from all strategies 2020-04-28 16:13:33 +02:00
Kubernetes Prow Robot
149085fb57 Merge pull request #240 from ingvagabund/turn-strategy-params-NodeResourceUtilizationThresholds-field-into-pointer
Turn StrategyParameters.NodeResourceUtilizationThresholds field into a pointer
2020-04-28 06:48:07 -07:00
Jan Chaloupka
991eddb691 Turn StrategyParameters.NodeResourceUtilizationThresholds field into a pointer
The field is intended to be omitempty when not set. Without a pointer the strategy
serialized into json string looks like:

```json
strategies:
  LowNodeUtilization:
    enabled: true
    params:
      nodeResourceUtilizationThresholds:
        numberOfNodes: 1
        targetThresholds:
          cpu: 50
          memory: 50
          pods: 20
        thresholds:
          cpu: 50
          memory: 50
          pods: 20
  RemoveDuplicates:
    enabled: true
    params:
      nodeResourceUtilizationThresholds: {}
  RemovePodsViolatingInterPodAntiAffinity:
    enabled: true
    params:
      nodeResourceUtilizationThresholds: {}
  RemovePodsViolatingNodeAffinity:
    enabled: true
    params:
      nodeAffinityType:
      - requiredDuringSchedulingIgnoredDuringExecution
      nodeResourceUtilizationThresholds: {}
  RemovePodsViolatingNodeTaints:
    enabled: true
    params:
      nodeResourceUtilizationThresholds: {}
```

It's preferred to have the following json string instead:
```
strategies:
  LowNodeUtilization:
    enabled: true
    params:
      nodeResourceUtilizationThresholds:
        numberOfNodes: 1
        targetThresholds:
          cpu: 50
          memory: 50
          pods: 20
        thresholds:
          cpu: 50
          memory: 50
          pods: 20
  RemoveDuplicates:
    enabled: true
  RemovePodsViolatingInterPodAntiAffinity:
    enabled: true
  RemovePodsViolatingNodeAffinity:
    enabled: true
    params:
      nodeAffinityType:
      - requiredDuringSchedulingIgnoredDuringExecution
  RemovePodsViolatingNodeTaints:
    enabled: true
```
2020-04-28 15:20:30 +02:00
Kubernetes Prow Robot
91de471376 Merge pull request #254 from damemi/toomanyrestarts
Add RemoveTooManyRestarts policy
2020-04-27 12:48:05 -07:00
Mike Dame
c2d7e22749 make gen && go mod vendor 2020-04-24 10:48:28 -04:00
Mike Dame
e7c42794a0 Add RemovePodsHavingTooManyRestarts strategy 2020-04-24 10:48:28 -04:00
Kubernetes Prow Robot
3a8dfc07ed Merge pull request #266 from ingvagabund/pod-evictor
Move maximum-pods-per-nodes-evicted logic under a single invocation
2020-04-23 16:14:07 -07:00
Jan Chaloupka
077b7f6505 Drop check for MaxNoOfPodsToEvictPerNode and invoke EvictPod wrapper instead 2020-04-22 10:33:22 +02:00
Jan Chaloupka
240fa93bc5 Move maximum-pods-per-nodes-evicted logic under a single invocation
Each strategy implements a test for checking if a maximum number of pods per node
was already evicted. The test duplicates a code that can be put
under a single invocation. Thus, reducing the number of arguments passed
to each strategy given EvicPod call can encapsulate both the check
and the invocation of the pod eviction itself.
2020-04-22 10:32:16 +02:00
Kubernetes Prow Robot
6c7f846917 Merge pull request #265 from ingvagabund/tolerations-tains-code-cleanup
Tolerations taints code cleanup
2020-04-21 14:27:52 -07:00
Jan Chaloupka
6db7c3b92c Call utils.TolerationsTolerateTaintsWithFilter directly, not through checkPodsSatisfyTolerations 2020-04-21 22:34:14 +02:00
Kubernetes Prow Robot
030267107a Merge pull request #262 from ingvagabund/order-pods-by-priority-only-over-over-utilized-nodes
Order pods by priority only over over utilized nodes
2020-04-19 14:05:38 -07:00
Jan Chaloupka
1c300a9881 Drop getNoScheduleTaints and allTaintsTolerated in favor of utils.TolerationsTolerateTaintsWithFilter 2020-04-19 22:18:49 +02:00
Jan Chaloupka
0e9b33b822 allTaintsTolerated: remove for iteration through tolerations which is already implemented in utils.TolerationsTolerateTaint 2020-04-19 22:07:34 +02:00
Jan Chaloupka
36e3d1e703 Drop local implementation of toleratesTaint in favor of k8s.io/api/core/v1.Toleration.TolerateTaint
Functionally identical implementation of toleratesTaint is already provided in k8s.io/api
2020-04-19 21:58:41 +02:00
Jan Chaloupka
f53264b613 lownodeutilization: evict best-effort pods only
Unit test refactored node utilization and pod clasification
2020-04-17 11:32:34 +02:00
Jan Chaloupka
414554ae5e lownodeutilization: make unit tests with/without priority table driven 2020-04-17 11:32:28 +02:00
Jan Chaloupka
150f945592 lownodeutilization: clasify pods of over utilized nodes only
Only over utilized nodes need clasification of pods into categories.
Thus, skipping categorizing of pods which saves computation time in cases
where the number of over utilized nodes makes less than 50% of all nodes
or their fraction.
2020-04-17 11:32:22 +02:00
Kubernetes Prow Robot
9a84afece1 Merge pull request #264 from ingvagabund/remove-pods-violating-node-affinity
readme: RemovePodsViolatingNodeAffinity: reword description of the strategy
2020-04-16 20:59:08 -07:00
Jan Chaloupka
e0c101c5ae readme: RemovePodsViolatingNodeAffinity: reword description of the strategy
Compared to https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity
the strategy kinda implements requiredDuringSchedulingRequiredDuringExecution node affinity type
for kubelets. Only addition to kubelet is the strategy checks whether is at least another node
capable of respecting the node affinity rules.

When requiredDuringSchedulingRequiredDuringExecution node affinity type is implemented in kubelet,
it's likely the strategy either gets removed or re-implemented. Stressing the relation with
requiredDuringSchedulingRequiredDuringExecution will helps consumers of descheduler
to keep in mind the kubelet will eventually take over the strategy when implemented.
2020-04-15 11:54:37 +02:00
Kubernetes Prow Robot
e3a562aea0 Merge pull request #260 from CriaHu/hyq_descheduler
fix broken link :
2020-04-07 18:01:44 -07:00
Kubernetes Prow Robot
4966e8ee08 Merge pull request #256 from damemi/fix-podfitsanynode
Fix early return from PodFitsAnyNode check
2020-04-07 08:01:43 -07:00
Kubernetes Prow Robot
d3542d5892 Merge pull request #258 from damemi/verify-deps
Add verify-vendor scripts to CI
2020-04-07 07:53:43 -07:00
Mike Dame
62d04b0fc7 go mod tidy && go mod vendor 2020-04-07 10:34:47 -04:00
Mike Dame
6ecbc85448 Add hack/{update,verify}-vendor.sh scripts 2020-04-07 10:34:47 -04:00
Cria Hu
b9b1eae6fb fix broken link :
https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md
2020-04-06 09:28:09 +08:00
Mike Dame
e95e42930d Remove early return false from PodFitsAnyNode 2020-04-02 11:53:29 -04:00
Kubernetes Prow Robot
3cabb69014 Merge pull request #255 from KohlsTechnology/go-1.13.9
Update to Go 1.13.9
2020-03-31 20:47:27 -07:00
Sean Malloy
ad8f90f177 Update to Go 1.13.9
Kubernetes releases 1.16 through 1.19 have been updated
to Go 1.13.9, so it's time to update the descheduler too.
2020-03-31 22:30:52 -05:00
Kubernetes Prow Robot
8a62cf1699 Merge pull request #246 from KohlsTechnology/go-1.13.8
Update to Go 1.13.8
2020-03-09 11:17:36 -07:00
Sean Malloy
a6b54dae99 Update to Go 1.13.8
Kubernetes releases 1.15 through 1.19 have been updated
to Go 1.13.8, so it's time to update the descheduler too.

https://github.com/kubernetes/release/issues/1134
2020-03-08 23:12:53 -05:00
Kubernetes Prow Robot
112684bcb9 Merge pull request #181 from jw-s/feature/respect-tolerations
Respect Node taints with tolerations (if exist)
2020-03-04 10:45:48 -08:00
Kubernetes Prow Robot
682e07c3cd Merge pull request #249 from ingvagabund/list-node-through-informer-in-every-iteration
List nodes through informer in every iteration
2020-03-04 10:43:48 -08:00
Jan Chaloupka
9593ce16d9 List nodes through informer in every iteration
Also, refactor the code a bit so it can be tested without checking for eviction support.
2020-03-04 16:26:13 +01:00
Kubernetes Prow Robot
2545c8b031 Merge pull request #244 from KohlsTechnology/docs-revamp
Documentation Refresh
2020-03-04 07:23:47 -08:00
Sean Malloy
c9793e7029 Clean README based on feedback from review 2020-03-03 22:07:20 -06:00
Joel Whittaker-Smith
4757132452 check for taints on low nodes and honor them 2020-03-02 14:43:11 +01:00
Sean Malloy
561b3b67b3 Clean README based on feedback from review 2020-02-28 22:38:28 -06:00
Sean Malloy
566f33e6ad Initial User and Contributor Guide Draft 2020-02-26 01:29:57 -06:00
Sean Malloy
83a75bac80 Create Structure and Links For User and Contributor Guides 2020-02-26 01:30:08 -06:00
Sean Malloy
d8772f5685 Clean up README
* Fixed small typos
* Update compatability matrix
2020-02-26 01:29:57 -06:00
Kubernetes Prow Robot
df510187d6 Merge pull request #233 from KohlsTechnology/update-release-docs
Add notes section to release documentation
2020-02-21 11:12:12 -08:00
Kubernetes Prow Robot
137b9b72e7 Merge pull request #242 from KohlsTechnology/fix-gcr-registry
Fix GCR Image Location In Job and CronJob YAML
2020-02-20 09:41:01 -08:00
Sean Malloy
09b4979673 Fix GCR Image Location In Job and CronJob YAML
The correct location for the official descheduler container image is
us.gcr.io/k8s-artifacts-prod/descheduler/descheduler:TAG_NAME.
2020-02-20 00:30:16 -06:00
Kubernetes Prow Robot
eff8185d7c Merge pull request #239 from aveshagarwal/master-fix-gen
Fix email address in docker files.
2020-02-12 07:04:52 -08:00
Avesh Agarwal
83ee94dd08 Fix email address in docker files. 2020-02-12 09:31:24 -05:00
Sean Malloy
aae52ac2ee Document gcloud command used to get container image details
The "gcloud container images describe" command is used to get the SHA256
hash of an image in the staging registry. The SHA256 hash is required
for the image promotion process.

https://github.com/kubernetes/k8s.io/tree/master/k8s.gcr.io#image-promoter
2020-02-11 22:46:27 -06:00
Sean Malloy
a7c4295c58 Add notes section to release documentation
Add a link to the test grid dashboard for automated container image builds,
and documents useful gcloud commands for woking with the staging registry.

This documentation is useful for project maintainers that are creating
releases and publishing container images. The chance of remembering
these commands and links is slim to none. Therefore documenting this
information will be very useful.
2020-02-11 22:41:35 -06:00
Kubernetes Prow Robot
7a6e095451 Merge pull request #222 from KohlsTechnology/travis-build-matrix
Run e2e Tests Against Multiple k8s Versions
2020-02-11 18:30:07 -08:00
Kubernetes Prow Robot
28c17d240d Merge pull request #237 from KohlsTechnology/issue-229
Update ClusterRole To Allow Creating Events
2020-02-11 18:28:07 -08:00
Sean Malloy
6dd91b6a22 Update ClusterRole To Allow Updating Events
Based on feedback during code review it was recommended to allow
updating events in addition to creating events. Because event proceeding
logic on the client side sometimes updates existing events instead of
creating a new one.
2020-02-09 00:17:20 -06:00
Sean Malloy
7d93551c34 Run e2e Tests Against Multiple k8s Versions
Enable a build matrix in Travis CI to run the e2e tests against
multiple k8s versions. Additionally update kind to v0.7.0 which adds
support for k8s v1.17.

Replaced command "kind get kubeconfig-path" with "kind get kubeconfig"
because the "kubeconfig-path" subcommand is not valid with kind v0.7.0.
2020-02-07 22:27:00 -06:00
Sean Malloy
853c43737d Update ClusterRole To Allow Creating Events
The descheduler creates a k8s event for each pod that it evicts. When
the code to create events was added the RBAC ClusterRole was not updated
to allow creating events. Users would see the below error in the
descheduler log when it tried to create an event.

"system:serviceaccount:kube-system:descheduler-sa" cannot create resource
"events" in API group "" in the namespace "xxxx-production"' (will not retry!)'

This change fixes this error by updating the ClusterRole to allow
creation of k8s events.
2020-02-07 22:03:14 -06:00
Kubernetes Prow Robot
d8dab9d134 Merge pull request #236 from aveshagarwal/master-fix-gen
Fix makefile for make gen, and update hack files and auto-generated files.
2020-02-07 13:57:46 -08:00
Avesh Agarwal
8dc7b475d9 Fix makefile for make gen, and Update hack files and
auto-generated files.
2020-02-07 16:32:55 -05:00
Kubernetes Prow Robot
15a971494e Merge pull request #208 from KohlsTechnology/install-docs
Streamline Deployment Docs For End Users
2020-02-07 09:27:45 -08:00
Kubernetes Prow Robot
5364e17c62 Merge pull request #215 from tambetliiv/patch-1
fix Build and Run GOPATH dir
2020-02-07 08:19:47 -08:00
Kubernetes Prow Robot
fc8c581d7a Merge pull request #226 from ankon/pr/node-unschedulable-typo
Fix typo in function name
2020-02-07 08:13:47 -08:00
Kubernetes Prow Robot
d7482bd618 Merge pull request #234 from ingvagabund/drop-critical-pod-annotation
Critical pod annotation scheduler.alpha.kubernetes.io/critical-pod has been drop, no need to set it anymore in the tests
2020-02-07 08:09:45 -08:00
Jan Chaloupka
d065f9904b Critical pod annotation scheduler.alpha.kubernetes.io/critical-pod has been drop, no need to set it anymore in the tests 2020-02-07 16:29:44 +01:00
Sean Malloy
fb8cdc10c7 Update Container Image Registry
Change the Job and CronJob YAML manifests to use container image
registry us.gcr.io/k8s-artifacts-prod/descheduler. This is the new
official location for the descheduler container image that is very close
to being all setup.
2020-02-06 23:20:33 -06:00
Sean Malloy
55cf45a6ba Streamline Deployment Docs For End Users
The k8s YAML manifests for deploying the descheduler as a k8s job were
duplicated across the "examples" and "kubernetes" directories and also
in README.md. This change consolidates the YAML manifests into the
"kubernetes" directory and simplifies the installation instructions for end
users in README.md.

Additionally a k8s CronJob has been added.
2020-02-06 23:20:33 -06:00
Kubernetes Prow Robot
e2a23f2848 Merge pull request #216 from damemi/remove-k8s-deps
Remove k8s.io/kubernetes deps and switch to go modules
2020-02-06 12:21:26 -08:00
Kubernetes Prow Robot
c567768845 Merge pull request #227 from KohlsTechnology/pod-priority-docs
Remove reference to critical-pod annotation from documentation
2020-02-06 07:53:34 -08:00
Sean Malloy
9510891f42 Remove reference to critical-pod annotation from documentation
Newer versions of k8s(>= 1.16) no longer support the critical-pod
annotation. Setting the priorityClassName is the correct way to mark a
pod as critical.

https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods
2020-02-04 23:27:25 -06:00
Kubernetes Prow Robot
73858beeea Merge pull request #223 from KohlsTechnology/bump-go-version
Update to Go 1.13.6
2020-02-04 15:59:54 -08:00
Andreas Kohn
c3346e9806 Fix typo in function name 2020-02-04 10:03:08 +01:00
Mike Dame
cc92eaa35d Run go mod vendor again to remove more deps 2020-02-03 10:05:04 -05:00
Mike Dame
816f8cb682 Fix build errors 2020-02-03 10:05:04 -05:00
Mike Dame
5f12ade97b go mod vendor 2020-02-03 10:05:04 -05:00
Mike Dame
2b68e65238 Remove old vendor, glide.lock/yaml 2020-02-03 10:05:03 -05:00
Mike Dame
86d0f3b038 go mod init/tidy 2020-02-03 10:04:58 -05:00
Mike Dame
c9f64dfe37 glide up -v 2020-02-03 10:04:58 -05:00
Mike Dame
431597dd43 Break dependency on k8s.io/kubernetes 2020-02-03 10:04:53 -05:00
Kubernetes Prow Robot
861f057d1b Merge pull request #217 from KohlsTechnology/cloud-build-config
Automate Container Image Builds Using GCB
2020-02-03 06:55:22 -08:00
Kubernetes Prow Robot
d845040d77 Merge pull request #221 from damemi/descheduling-interval
Wire --descheduling-interval to run descheduler on a loop
2020-02-03 05:53:21 -08:00
Mike Dame
30d05382b6 Wire --descheduler-interval flag to run descheduler on a loop 2020-01-30 17:17:55 -05:00
Kubernetes Prow Robot
ca02665d14 Merge pull request #218 from KohlsTechnology/update-owners
Add seanmalloy to reviewers
2020-01-30 12:10:19 -08:00
Sean Malloy
2328d89897 Update to Go 1.13.6
The kubernetes project updated to Go 1.13.6, so it's time to update the
descheduler too.

https://github.com/kubernetes/kubernetes/pull/87106
2020-01-30 01:41:36 -06:00
Sean Malloy
ac089fe5ce Document Descheduler Release Process 2020-01-29 23:32:37 -06:00
Sean Malloy
00e23dbc07 Add seanmalloy to reviewers 2020-01-27 21:21:24 -06:00
Sean Malloy
3401edab53 Automate Container Image Builds Using GCB
Adds a GCB(Google Cloud Build) configuraiton file that automates the
building and pushing of descheduler container images to the official
Google Container Registry for k8s.

Reference documentation:
https://github.com/kubernetes/test-infra/blob/master/config/jobs/image-pushing/README.md
2020-01-25 21:56:11 -06:00
Kubernetes Prow Robot
e3865fcf8e Merge pull request #173 from KohlsTechnology/new-staging-repo
Use correct GCR staging registry
2020-01-24 07:36:32 -08:00
Sean Malloy
361aa01c51 Remove backticks from Makefile 2020-01-24 09:00:54 -06:00
tambetliiv
c77f240e37 fix README gopath build
was not changed in https://github.com/kubernetes-sigs/descheduler/pull/182
2020-01-24 13:19:26 +02:00
Kubernetes Prow Robot
d9a77393cc Merge pull request #213 from mdavidsen/docs/update-examples
Update examples to support v1.16.0+
2020-01-18 07:05:35 -08:00
Marius Davidsen
44c7eb5285 Update examples to support v1.16.0+
Support for using the `scheduler.alpha.kubernetes.io/critical-pod` annotation was
deprectated in 1.13 and finally removed in 1.16.
2020-01-17 14:24:37 +01:00
Sean Malloy
462bbbbb47 Use correct GCR staging registry
The container registry now defaults to
the correct staging registry.
2020-01-09 22:16:14 -06:00
Kubernetes Prow Robot
18e3fd3de5 Merge pull request #210 from KohlsTechnology/update-kind
Update Travis With Latest Kind and Kubectl Versions
2020-01-03 02:01:41 -08:00
Sean Malloy
fdf94304d0 Update Travis With Latest Kind and Kubectl Versions
* Update to kubectl 1.17.0
* Update to kind 0.6.1
2019-12-18 21:11:11 -06:00
Kubernetes Prow Robot
ea0ba7d39a Merge pull request #209 from KohlsTechnology/go-1.13
Update To Go 1.13.5
2019-12-18 10:01:58 -08:00
Kubernetes Prow Robot
5be355d815 Merge pull request #204 from damemi/k8s-117-bump
Bump k8s deps to 1.17
2019-12-18 09:51:58 -08:00
Sean Malloy
5efec68fd3 Update To Go 1.13.5
Starting with Kubernetes release 1.17 Go >= 1.13.4 is required.

https://github.com/kubernetes/kubernetes/pull/82809
2019-12-18 00:26:25 -06:00
Mike Dame
b3cc62dac6 bump(*): k8s to 1.17 2019-12-12 11:02:29 -05:00
Mike Dame
3be0a9f80d Pin k8s deps to 1.17.0 2019-12-12 11:00:44 -05:00
Kubernetes Prow Robot
906bca0802 Merge pull request #174 from mccare/documentation-compile-and-example-yaml
Documentation for compile and example yaml files for creation of kubernetes resources
2019-12-12 07:54:32 -08:00
Kubernetes Prow Robot
d193bc1370 Merge pull request #183 from KohlsTechnology/k8s-events
Add k8s events support
2019-12-12 07:36:33 -08:00
Sean Malloy
6654aeff99 Update vendor directory for k8s events support
Executed "glide up -v" after adding the k8s event feature. These vendor
dependency changes are required for k8s event support.
2019-12-11 21:35:57 -06:00
Sean Malloy
e3d06d1541 Create k8s event when a pod is successfully evicted
This allows end users to more easily monitor when the descheduler evicts
a pod in their environment. Prior to adding k8s event support the only
way to track evicted pods was to view the logs.
2019-12-11 21:35:57 -06:00
Kubernetes Prow Robot
b44d7718b3 Merge pull request #201 from dileep-p/wront-intentation
Fix intentation on yaml
2019-12-02 07:43:04 -08:00
Dileep
531d6ddc49 Fix intentation on yaml 2019-11-28 12:36:45 +04:00
Kubernetes Prow Robot
bbc902b86f Merge pull request #197 from damemi/add-reviewer
Add damemi to reviewers
2019-11-13 13:58:55 -08:00
Mike Dame
1fdcbcd008 Add damemi to reviewers 2019-11-13 13:13:31 -05:00
Kubernetes Prow Robot
2fdcfc04d5 Merge pull request #194 from sivanzcw/develop
Normalize blank import
2019-11-09 09:07:39 -08:00
Zhang Jinghui
872953b9cf normalize blank import 2019-11-09 21:53:29 +08:00
Kubernetes Prow Robot
9276f0e555 Merge pull request #193 from mleneveut/master
Fix typos in kubernetes example
2019-11-08 06:50:13 -08:00
mleneveut
cee12a5019 Fix indentation 2019-11-08 15:29:48 +01:00
mleneveut
456110b508 Fix typo in ClusterRoleBinding name 2019-11-08 15:16:33 +01:00
Kubernetes Prow Robot
edab9d7fed Merge pull request #175 from swatisehgal/dev/strategyTaintTol
Strategy to consider taints and tolerations in Descheduler
2019-11-05 13:28:39 -08:00
swatisehgal
7563b5561b Strategy to consider taints and tolerations in Descheduler 2019-11-05 20:42:36 +00:00
Kubernetes Prow Robot
8b210b08f6 Merge pull request #192 from damemi/glog-klog-switch
Switch from glog to klog
2019-10-28 23:20:43 -07:00
Mike Dame
a3d33909fa bump(*): remove glog 2019-10-28 20:44:02 -04:00
Mike Dame
4b9e732c18 Switch from glog to klog 2019-10-28 20:44:02 -04:00
Kubernetes Prow Robot
dd54f1a656 Merge pull request #188 from damemi/k8s-1.16
Bump to k8s 1.16
2019-10-22 09:07:22 -07:00
Mike Dame
11044ed89d Run generated scripts 2019-10-21 13:33:39 -04:00
Mike Dame
e5d4a2eba6 bump(*): Remove codecgen dependency 2019-10-21 13:33:38 -04:00
Mike Dame
c9e3c63b85 Remove codecgen
Since [1] codecgen has been obsolete.

[1] https://github.com/kubernetes/kubernetes/issues/36120
2019-10-21 13:33:38 -04:00
Mike Dame
5b1d551ffd update e2e test 2019-10-21 13:33:38 -04:00
Mike Dame
b176dd2e77 Remove old NodeOutOfDisk unit test 2019-10-21 13:33:38 -04:00
Mike Dame
9ea6aa536e Update CriticalPod unit test
The kubelet used to only determine critical pods by the namespace and an annotation (see [1], where our code switched from only checking the annotation to using the kubelet package helper, which at that revision also only checked for an annotation and namespace). However, now the kubelet uses Pod Priority to check for critical pods[3], which is controlled by an admission plugin[4]. Given that testing the functioning of the admission plugin is out of the scope of this repository, it is probably sufficient to manually set the pod priority to critical, to ensure that our Descheduler code behaves properly in response.

[1] 062b8698c7 (diff-094ac8507e224603239ce19592b518f5)
[2] https://github.com/kubernetes/kubernetes/blob/release-1.9/pkg/kubelet/types/pod_update.go#L151
[3] https://github.com/kubernetes/kubernetes/blob/a847874655/pkg/kubelet/types/pod_update.go#L153
[4] https://github.com/kubernetes/kubernetes/blob/a847874655/plugin/pkg/admission/priority/admission.go
2019-10-21 13:33:38 -04:00
Mike Dame
bd2c217010 update makefile/dockerfile to use golang 1.12.12 2019-10-21 13:33:15 -04:00
Kubernetes Prow Robot
c42670e1cc Merge pull request #190 from bysph/master
Fix golint errors
2019-10-17 06:32:39 -07:00
sph
5e25e21ca2 Fix golint errors
Signed-off-by: sph <shepenghui1@huawei.com>
2019-10-17 20:50:13 +08:00
Mike Dame
0af97c1b5e fix compile errors 2019-10-12 11:12:04 -04:00
Mike Dame
1652ba7976 bump(*): kubernetes release-1.16.0 dependencies 2019-10-12 11:11:43 -04:00
Mike Dame
5af668e89a Remove old API install patterns 2019-10-12 11:08:46 -04:00
Mike Dame
26adf87323 Bump reactions
Change imports to reflect current component-base usage
2019-10-12 11:07:21 -04:00
Mike Dame
0a58cf4535 Update glide.yaml 2019-10-12 11:06:42 -04:00
Kubernetes Prow Robot
3116dad75e Merge pull request #186 from ksimon1/master
Evict annotation
2019-10-11 02:45:42 -07:00
ksimon1
fb1b5fc690 added unit test
updated e2e test

Signed-off-by: ksimon1 <ksimon@redhat.com>
2019-10-04 11:08:33 +02:00
ksimon1
dc7f9efc19 Descheduler can evict all types of pods with special annotation
When pod has this annotation, descheduler will always try to evict this pod.
User can control which pods (only pods with this annotation) will be evicted.
Signed-off-by: ksimon1 <ksimon@redhat.com>
2019-10-04 11:07:40 +02:00
Kubernetes Prow Robot
f1127541aa Merge pull request #182 from ingvagabund/rename-import-path-prefix
Project migrated under kubernetes-sigs, change import path prefix to sigs.k8s.io/descheduler
2019-09-19 06:23:00 -07:00
Jan Chaloupka
9d6b6094cd Explicitly set the repository root directory
Looks like Travis does not honor the new repository location.
2019-09-19 15:03:45 +02:00
Jan Chaloupka
e35eb4a0b5 Run ./hack/update-gofmt 2019-09-19 14:29:00 +02:00
Jan Chaloupka
2e6f14103b Project migrared under kubernetes-sigs, change import path prefix to sigs.k8s.io/descheduler 2019-09-19 14:09:05 +02:00
Avesh Agarwal
17ef1d5e5f Merge pull request #179 from mrbobbytables/update-owners-sec-contacts
Update OWNERS and SECURITY_CONTACTS
2019-09-14 14:19:30 -04:00
Kubernetes Prow Robot
7788d53d0b Merge pull request #178 from danedf/master
Fix small typo in output for thresholds
2019-09-14 07:42:39 -07:00
Bob Killen
5f66ed8401 Update OWNERS and SECURITY_CONTACTS 2019-09-12 08:09:47 -04:00
Dane De Forest
cd4d09726c Fix small typo in output for thresholds for low utilization 2019-08-28 11:25:55 -07:00
Christian van der Leeden
68a106aed0 changed policy, RemoveDuplicates is not automatically turned on, so used the policy.yaml file from the examples 2019-08-03 11:41:52 +02:00
Christian van der Leeden
1931bd6c1a created example yaml files out of the readme instructions with a reference to the 0.9.0 docker image. Modified the readme so the make will work since it expects a certain file structure 2019-08-01 12:05:13 +02:00
Kubernetes Prow Robot
9e28f0b362 Merge pull request #169 from Bowenislandsong/fix-test
Remove hardcoded node selection in E2e test
2019-07-12 13:55:05 -07:00
Bowen Song
7245a31f52 Change hard coded leastLoadedNode=[3rd node] to searching for leastLoadedNode worker node
Accomodate dee89a6cc1

And format files according to gofmt verification

update version to 1.11.1
2019-07-11 17:26:06 -04:00
ravisantoshgudimetla
66a2a87e49 Start use kind for e2e tests 2019-07-11 10:03:06 -04:00
Kubernetes Prow Robot
e7ceddf2bc Merge pull request #162 from tammert/duplicate-test-logic-rework
Improved logic for duplicates testing
2019-07-05 08:00:38 -07:00
Kubernetes Prow Robot
e3d25a9ab4 Merge pull request #165 from KohlsTechnology/add-gitignore
Add .gitignore to ignore output directory for binaries
2019-07-05 06:40:35 -07:00
Sean Malloy
992e00ecd2 Add .gitignore to ignore output directory for binaries 2019-07-04 22:09:28 -05:00
Kubernetes Prow Robot
d157a4359b Merge pull request #160 from KohlsTechnology/issue-144
Push Container Images To k8s.gcr.io
2019-06-20 06:32:52 -07:00
Sean Malloy
6a08b5661a Changes image variable name based on code review comments 2019-06-20 01:00:01 -05:00
Sean Malloy
7094c404c9 Change push-container to push-container-to-gcloud
Changes made based on code review comments.
2019-06-19 00:51:31 -05:00
Sebastiaan Tammer
20c610c65a Improved logic for duplicates testing 2019-06-11 20:35:55 +02:00
Sean Malloy
934a06381d Push Container Images To k8s.gcr.io
Run below commands to build and push
a staging image to staging-k8s.gcr.io.

```
$ make push
```

Run below commands to build and push
a release image to k8s.gcr.io.

```
$ git checkout v0.9.0
$ VERSION=v0.9.0 REGISTRY=k8s.gcr.io make push
```
2019-06-05 00:35:10 -05:00
Kubernetes Prow Robot
674c1db05c Merge pull request #149 from reetasingh/master
Adding golang ci lint support and Refactoring test by make it table driven
2019-06-04 07:25:11 -07:00
Reeta Singh
dee89a6cc1 Refactoring test by make it table driven and adding golangci-lint to the CI pipeline 2019-06-03 20:40:02 -07:00
Kubernetes Prow Robot
60fbaca305 Merge pull request #156 from tammert/identical-deployments-fix
Added ownerRef.UID for evaluating duplicate Pods
2019-06-02 11:26:13 -07:00
Sebastiaan Tammer
164d2b0729 Minor typo corrected 2019-05-25 11:40:03 +02:00
Sebastiaan Tammer
023a2f2a47 Replaced UID with Namespace for duplicate check, added tests (+ cleanup) 2019-05-25 11:18:11 +02:00
Sebastiaan Tammer
d1c6f3f709 Added ownerRef.UID for evaluating duplicate Pods 2019-05-24 18:51:33 +02:00
Kubernetes Prow Robot
fc1688057a Merge pull request #142 from adyada/master
Added support to evict pods that use local storage.
2019-04-12 07:42:46 -07:00
Adi Yadav
e6e200b93c Added auto-generated changes. 2019-04-11 23:24:56 -04:00
Adi Yadav
5d843d1f08 Added manual changes. 2019-04-11 23:24:20 -04:00
Kubernetes Prow Robot
6c981cc067 Merge pull request #137 from pickledrick/fix/update-installation-readme
update readme to fix unused path
2019-03-04 06:04:39 -08:00
Peter Grant
22a3a6ea1d update readme to fix unused path 2019-03-04 15:16:37 +11:00
Kubernetes Prow Robot
294bddb5e2 Merge pull request #135 from russiancook/patch-1
Update configmap.yaml
2019-02-28 13:34:37 -08:00
russiancook
0a9d1959e2 Update configmap.yaml
Put configmap in kube-system namespace
2019-02-14 12:12:47 +02:00
RaviSantosh Gudimetla
19ee5d80b5 Merge pull request #124 from ravisantoshgudimetla/fix-kubeadm
Run apiserver on private ip and bump kube version installed to 1.13
2019-01-14 22:41:26 -05:00
ravisantoshgudimetla
14d9e175c2 Run apiserver on private ip and bump kube version installed to 1.13 2018-12-14 14:54:42 -05:00
RaviSantosh Gudimetla
468e138070 Merge pull request #114 from nikhita/contributing.md
Add CONTRIBUTING.md
2018-09-03 09:15:37 -04:00
Nikhita Raghunath
db13b2ac73 Add CONTRIBUTING.md 2018-09-01 19:29:24 +05:30
Avesh Agarwal
40ca53e0a5 Merge pull request #113 from sanity-io/master
Yaml files for kubernetes
2018-08-24 08:50:41 -04:00
nicholas.klem
35d8367fe5 rbac.authorization.k8s.io/v1 - not v1beta1 2018-08-24 14:44:19 +02:00
nicholas.klem
345dd9cf27 add kubernetes yaml files 2018-08-24 14:34:38 +02:00
RaviSantosh Gudimetla
81f471fe05 Merge pull request #111 from kubernetes-incubator/ravisantoshgudimetla-patch-2
Remove production usage warning
2018-08-23 15:57:09 -04:00
RaviSantosh Gudimetla
aa5e8770f5 Remove production usage warning
Removing production usage warning to encourage more users to try using descheduler and since descheduler has been stable so far.
2018-08-23 15:44:17 -04:00
RaviSantosh Gudimetla
2690d139c5 Merge pull request #110 from kubernetes-incubator/ravisantoshgudimetla-patch-1
Update the compatibility matrix
2018-08-22 16:31:09 -04:00
RaviSantosh Gudimetla
cd192ce5fc Update the compatibility matrix
Descheduler 0.4+ should work with kube 1.9+.
2018-08-22 16:09:18 -04:00
RaviSantosh Gudimetla
048f3fd1e5 Merge pull request #109 from ravisantoshgudimetla/test-cases-cleanup
Remove the unnecessary print statements in test file
2018-08-22 12:20:27 -04:00
ravisantoshgudimetla
a079fd2757 Remove the unnecessary print statements 2018-08-22 11:27:40 -04:00
RaviSantosh Gudimetla
ae0a9ed525 Merge pull request #108 from ravisantoshgudimetla/fix-warnings-ci
Fix deprecated warning in CI
2018-08-21 15:10:40 -04:00
ravisantoshgudimetla
0a815e8786 Fix deprecated warning in CI 2018-08-21 14:45:14 -04:00
RaviSantosh Gudimetla
0115748fe8 Merge pull request #105 from ravisantoshgudimetla/priority-low-node
Low node utilization to respect priority while evicting pods
2018-08-21 14:33:50 -04:00
ravisantoshgudimetla
d0305dac3f Low node utilization to respect priority while evicting pods 2018-08-21 14:14:26 -04:00
RaviSantosh Gudimetla
72d6a8aa33 Merge pull request #106 from ravisantoshgudimetla/fix-e2e
Fix broken e2e tests
2018-08-06 10:53:13 -04:00
ravisantoshgudimetla
654fdbba94 Fix broken e2e tests 2018-08-05 13:16:47 -04:00
Avesh Agarwal
d73471327b Merge pull request #99 from aveshagarwal/master-fix-1
Add SECURITY_CONTACTS file.
2018-05-31 12:05:58 -04:00
Avesh Agarwal
1294c8a2c2 Add SECURITY_CONTACTS file. 2018-05-31 11:46:54 -04:00
Avesh Agarwal
ddd3dd6f19 Merge pull request #95 from betabrand/auth-providers
Allow other auth providers (GCP, OIDC, Azure, OpenStack)
2018-05-23 13:01:27 -04:00
Hugues Alary
fad9e8dc39 Running glide update -v to pulldown all the required depedencies 2018-05-22 19:14:00 -07:00
Hugues Alary
450a5c290b Allow other auth providers (GCP, OIDC, Azure, OpenStack) 2018-05-22 19:13:47 -07:00
RaviSantosh Gudimetla
af2198428e Merge pull request #94 from ingvagabund/travis-bump-go-to-1.10
Bump Travis go version to 1.9.1
2018-05-22 09:39:29 -04:00
Jan Chaloupka
bc7be54e2e Bump Travis go version to 1.9.1 2018-05-22 14:50:20 +02:00
Avesh Agarwal
ccb61fc800 Merge pull request #91 from aveshagarwal/master-critical-pod
Fix readme to have empty value for critical pod annotation as required.
2018-05-10 17:22:53 -04:00
Avesh Agarwal
61819e3fec Fix readme to have empty value for critical pod annotation as required. 2018-05-10 16:44:40 -04:00
Avesh Agarwal
a7ceb67109 Merge pull request #88 from aveshagarwal/master-issues
Fix dryRun issue and avoid unnecessary log msg when node affinity strategy is disabled.
2018-04-24 09:48:05 -04:00
Avesh Agarwal
57a28e9a8f Fix dryRun issue and avoid unnecessary log
msg when node affinity strategy is disabled.
2018-04-23 17:13:19 -04:00
Avesh Agarwal
c1d87dd93c Merge pull request #87 from aveshagarwal/master-pod-max-issue
Fix max pods to evict per node.
2018-04-13 14:38:02 -04:00
Avesh Agarwal
34fb602101 Fix max pods to evict per node. 2018-04-12 15:28:24 -04:00
18607 changed files with 762 additions and 5025433 deletions

View File

@@ -1,7 +0,0 @@
language: go
go:
- 1.8.3
script:
- hack/verify-gofmt.sh
- make build
- make test-unit

View File

@@ -1,26 +0,0 @@
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM golang:1.9.2
WORKDIR /go/src/github.com/kubernetes-incubator/descheduler
COPY . .
RUN make
FROM scratch
MAINTAINER Avesh Agarwal <avagarwa@redhat.com>
COPY --from=0 /go/src/github.com/kubernetes-incubator/descheduler/_output/bin/descheduler /bin/descheduler
CMD ["/bin/descheduler", "--help"]

View File

@@ -1,20 +0,0 @@
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM scratch
MAINTAINER Avesh Agarwal <avagarwa@redhat.com>
COPY _output/bin/descheduler /bin/descheduler
CMD ["/bin/descheduler", "--help"]

201
LICENSE
View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,54 +0,0 @@
# Copyright 2017 The Kubernetes Authors.
# #
# # Licensed under the Apache License, Version 2.0 (the "License");
# # you may not use this file except in compliance with the License.
# # You may obtain a copy of the License at
# #
# # http://www.apache.org/licenses/LICENSE-2.0
# #
# # Unless required by applicable law or agreed to in writing, software
# # distributed under the License is distributed on an "AS IS" BASIS,
# # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# # See the License for the specific language governing permissions and
# # limitations under the License.
.PHONY: test
# VERSION is currently based on the last commit
VERSION=`git describe --tags`
COMMIT=`git rev-parse HEAD`
BUILD=`date +%FT%T%z`
LDFLAG_LOCATION=github.com/kubernetes-incubator/descheduler/cmd/descheduler/app
LDFLAGS=-ldflags "-X ${LDFLAG_LOCATION}.version=${VERSION} -X ${LDFLAG_LOCATION}.buildDate=${BUILD} -X ${LDFLAG_LOCATION}.gitCommit=${COMMIT}"
# IMAGE is the image name of descheduler
# Should this be changed?
IMAGE:=descheduler:$(VERSION)
all: build
build:
CGO_ENABLED=0 go build ${LDFLAGS} -o _output/bin/descheduler github.com/kubernetes-incubator/descheduler/cmd/descheduler
dev-image: build
docker build -f Dockerfile.dev -t $(IMAGE) .
image:
docker build -t $(IMAGE) .
clean:
rm -rf _output
test-unit:
./test/run-unit-tests.sh
test-e2e:
./test/run-e2e-tests.sh
gen:
./hack/update-codecgen.sh
./hack/update-generated-conversions.sh
./hack/update-generated-deep-copies.sh
./hack/update-generated-defaulters.sh

8
OWNERS
View File

@@ -1,8 +0,0 @@
approvers:
- aveshagarwal
- ravisantoshgudimetla
- jayunit100
reviewers:
- aveshagarwal
- ravisantoshgudimetla
- jayunit100

295
README.md
View File

@@ -1,295 +0,0 @@
[![Build Status](https://travis-ci.org/kubernetes-incubator/descheduler.svg?branch=master)](https://travis-ci.org/kubernetes-incubator/descheduler)
[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes-incubator/descheduler)](https://goreportcard.com/report/github.com/kubernetes-incubator/descheduler)
# Descheduler for Kubernetes
## Introduction
Scheduling in Kubernetes is the process of binding pending pods to nodes, and is performed by
a component of Kubernetes called kube-scheduler. The scheduler's decisions, whether or where a
pod can or can not be scheduled, are guided by its configurable policy which comprises of set of
rules, called predicates and priorities. The scheduler's decisions are influenced by its view of
a Kubernetes cluster at that point of time when a new pod appears first time for scheduling.
As Kubernetes clusters are very dynamic and their state change over time, there may be desired
to move already running pods to some other nodes for various reasons:
* Some nodes are under or over utilized.
* The original scheduling decision does not hold true any more, as taints or labels are added to
or removed from nodes, pod/node affinity requirements are not satisfied any more.
* Some nodes failed and their pods moved to other nodes.
* New nodes are added to clusters.
Consequently, there might be several pods scheduled on less desired nodes in a cluster.
Descheduler, based on its policy, finds pods that can be moved and evicts them. Please
note, in current implementation, descheduler does not schedule replacement of evicted pods
but relies on the default scheduler for that.
## Build and Run
Build descheduler:
```sh
$ make
```
and run descheduler:
```sh
$ ./_output/bin/descheduler --kubeconfig <path to kubeconfig> --policy-config-file <path-to-policy-file>
```
For more information about available options run:
```
$ ./_output/bin/descheduler --help
```
## Running Descheduler as a Job Inside of a Pod
Descheduler can be run as a job inside of a pod. It has the advantage of
being able to be run multiple times without needing user intervention.
Descheduler pod is run as a critical pod to avoid being evicted by itself,
or by kubelet due to an eviction event. Since critical pods are created in
`kube-system` namespace, descheduler job and its pod will also be created
in `kube-system` namespace.
### Create a container image
First we create a simple Docker image utilizing the Dockerfile found in the root directory:
```
$ make dev-image
```
This creates an image based off the binary we've built before. To build both the
binary and image in one step you can run the following command:
```
$ make image
```
This eliminates the need to have Go installed locally and builds the binary
within it's own container.
### Create a cluster role
To give necessary permissions for the descheduler to work in a pod, create a cluster role:
```
$ cat << EOF| kubectl create -f -
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: descheduler-cluster-role
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list", "delete"]
- apiGroups: [""]
resources: ["pods/eviction"]
verbs: ["create"]
EOF
```
### Create the service account which will be used to run the job:
```
$ kubectl create sa descheduler-sa -n kube-system
```
### Bind the cluster role to the service account:
```
$ kubectl create clusterrolebinding descheduler-cluster-role-binding \
--clusterrole=descheduler-cluster-role \
--serviceaccount=kube-system:descheduler-sa
```
### Create a configmap to store descheduler policy
Descheduler policy is created as a ConfigMap in `kube-system` namespace
so that it can be mounted as a volume inside pod.
```
$ kubectl create configmap descheduler-policy-configmap \
-n kube-system --from-file=<path-to-policy-dir/policy.yaml>
```
### Create the job specification (descheduler-job.yaml)
```
apiVersion: batch/v1
kind: Job
metadata:
name: descheduler-job
namespace: kube-system
spec:
parallelism: 1
completions: 1
template:
metadata:
name: descheduler-pod
annotations:
scheduler.alpha.kubernetes.io/critical-pod: "true"
spec:
containers:
- name: descheduler
image: descheduler
volumeMounts:
- mountPath: /policy-dir
name: policy-volume
command:
- "/bin/sh"
- "-ec"
- |
/bin/descheduler --policy-config-file /policy-dir/policy.yaml
restartPolicy: "Never"
serviceAccountName: descheduler-sa
volumes:
- name: policy-volume
configMap:
name: descheduler-policy-configmap
```
Please note that the pod template is configured with critical pod annotation, and
the policy `policy-file` is mounted as a volume from the config map.
### Run the descheduler as a job in a pod:
```
$ kubectl create -f descheduler-job.yaml
```
## Policy and Strategies
Descheduler's policy is configurable and includes strategies to be enabled or disabled.
Four strategies, `RemoveDuplicates`, `LowNodeUtilization`, `RemovePodsViolatingInterPodAntiAffinity`, `RemovePodsViolatingNodeAffinity` are currently implemented.
As part of the policy, the parameters associated with the strategies can be configured too.
By default, all strategies are enabled.
### RemoveDuplicates
This strategy makes sure that there is only one pod associated with a Replica Set (RS),
Replication Controller (RC), Deployment, or Job running on same node. If there are more,
those duplicate pods are evicted for better spreading of pods in a cluster. This issue could happen
if some nodes went down due to whatever reasons, and pods on them were moved to other nodes leading to
more than one pod associated with RS or RC, for example, running on same node. Once the failed nodes
are ready again, this strategy could be enabled to evict those duplicate pods. Currently, there are no
parameters associated with this strategy. To disable this strategy, the policy should look like:
```
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemoveDuplicates":
enabled: false
```
### LowNodeUtilization
This strategy finds nodes that are under utilized and evicts pods, if possible, from other nodes
in the hope that recreation of evicted pods will be scheduled on these underutilized nodes. The
parameters of this strategy are configured under `nodeResourceUtilizationThresholds`.
The under utilization of nodes is determined by a configurable threshold, `thresholds`. The threshold
`thresholds` can be configured for cpu, memory, and number of pods in terms of percentage. If a node's
usage is below threshold for all (cpu, memory, and number of pods), the node is considered underutilized.
Currently, pods' request resource requirements are considered for computing node resource utilization.
There is another configurable threshold, `targetThresholds`, that is used to compute those potential nodes
from where pods could be evicted. Any node, between the thresholds, `thresholds` and `targetThresholds` is
considered appropriately utilized and is not considered for eviction. The threshold, `targetThresholds`,
can be configured for cpu, memory, and number of pods too in terms of percentage.
These thresholds, `thresholds` and `targetThresholds`, could be tuned as per your cluster requirements.
An example of the policy for this strategy would look like:
```
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"LowNodeUtilization":
enabled: true
params:
nodeResourceUtilizationThresholds:
thresholds:
"cpu" : 20
"memory": 20
"pods": 20
targetThresholds:
"cpu" : 50
"memory": 50
"pods": 50
```
There is another parameter associated with `LowNodeUtilization` strategy, called `numberOfNodes`.
This parameter can be configured to activate the strategy only when number of under utilized nodes
are above the configured value. This could be helpful in large clusters where a few nodes could go
under utilized frequently or for a short period of time. By default, `numberOfNodes` is set to zero.
### RemovePodsViolatingInterPodAntiAffinity
This strategy makes sure that pods violating interpod anti-affinity are removed from nodes. For example, if there is podA on node and podB and podC(running on same node) have antiaffinity rules which prohibit them to run on the same node, then podA will be evicted from the node so that podB and podC could run. This issue could happen, when the anti-affinity rules for pods B,C are created when they are already running on node. Currently, there are no parameters associated with this strategy. To disable this strategy, the policy should look like:
```
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsViolatingInterPodAntiAffinity":
enabled: false
```
### RemovePodsViolatingNodeAffinity
This strategy makes sure that pods violating node affinity are removed from nodes. For example, there is podA that was scheduled on nodeA which satisfied the node affinity rule `requiredDuringSchedulingIgnoredDuringExecution` at the time of scheduling, but over time nodeA no longer satisfies the rule, then if another node nodeB is available that satisfies the node affinity rule, then podA will be evicted from nodeA. The policy file should like this -
```
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsViolatingNodeAffinity":
enabled: true
params:
nodeAffinityType:
- "requiredDuringSchedulingIgnoredDuringExecution"
```
## Pod Evictions
When the descheduler decides to evict pods from a node, it employs following general mechanism:
* Critical pods (with annotations scheduler.alpha.kubernetes.io/critical-pod) are never evicted.
* Pods (static or mirrored pods or stand alone pods) not part of an RC, RS, Deployment or Jobs are
never evicted because these pods won't be recreated.
* Pods associated with DaemonSets are never evicted.
* Pods with local storage are never evicted.
* Best efforts pods are evicted before Burstable and Guaranteed pods.
### Pod disruption Budget (PDB)
Pods subject to Pod Disruption Budget (PDB) are not evicted if descheduling violates its pod
disruption budget (PDB). The pods are evicted by using eviction subresource to handle PDB.
## Roadmap
This roadmap is not in any particular order.
* Strategy to consider taints and tolerations
* Consideration of pod affinity
* Strategy to consider pod life time
* Strategy to consider number of pending pods
* Integration with cluster autoscaler
* Integration with metrics providers for obtaining real load metrics
* Consideration of Kubernetes's scheduler's predicates
## Compatibility matrix
Descheduler | supported Kubernetes version
-------------|-----------------------------
0.4 | 1.9+
0.1-0.3 | 1.7-1.8
## Note
This project is under active development, and is not intended for production use.
Any api could be changed any time with out any notice. That said, your feedback is
very important and appreciated to make this project more stable and useful.

View File

@@ -1,60 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package options provides the descheduler flags
package options
import (
clientset "k8s.io/client-go/kubernetes"
// install the componentconfig api so we get its defaulting and conversion functions
"github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig"
_ "github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig/install"
"github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig/v1alpha1"
deschedulerscheme "github.com/kubernetes-incubator/descheduler/pkg/descheduler/scheme"
"github.com/spf13/pflag"
)
// DeschedulerServer configuration
type DeschedulerServer struct {
componentconfig.DeschedulerConfiguration
Client clientset.Interface
}
// NewDeschedulerServer creates a new DeschedulerServer with default parameters
func NewDeschedulerServer() *DeschedulerServer {
versioned := v1alpha1.DeschedulerConfiguration{}
deschedulerscheme.Scheme.Default(&versioned)
cfg := componentconfig.DeschedulerConfiguration{}
deschedulerscheme.Scheme.Convert(versioned, &cfg, nil)
s := DeschedulerServer{
DeschedulerConfiguration: cfg,
}
return &s
}
// AddFlags adds flags for a specific SchedulerServer to the specified FlagSet
func (rs *DeschedulerServer) AddFlags(fs *pflag.FlagSet) {
fs.DurationVar(&rs.DeschedulingInterval, "descheduling-interval", rs.DeschedulingInterval, "time interval between two consecutive descheduler executions")
fs.StringVar(&rs.KubeconfigFile, "kubeconfig", rs.KubeconfigFile, "File with kube configuration.")
fs.StringVar(&rs.PolicyConfigFile, "policy-config-file", rs.PolicyConfigFile, "File with descheduler policy configuration.")
fs.BoolVar(&rs.DryRun, "dry-run", rs.DryRun, "execute descheduler in dry run mode.")
// node-selector query causes descheduler to run only on nodes that matches the node labels in the query
fs.StringVar(&rs.NodeSelector, "node-selector", rs.NodeSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
// max-no-pods-to-evict limits the maximum number of pods to be evicted per node by descheduler.
fs.IntVar(&rs.MaxNoOfPodsToEvictPerNode, "max-pods-to-evict-per-node", rs.MaxNoOfPodsToEvictPerNode, "Limits the maximum number of pods to be evicted per node by descheduler")
}

View File

@@ -1,61 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package app implements a Server object for running the descheduler.
package app
import (
"flag"
"io"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler"
"github.com/golang/glog"
"github.com/spf13/cobra"
aflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/apiserver/pkg/util/logs"
)
// NewDeschedulerCommand creates a *cobra.Command object with default parameters
func NewDeschedulerCommand(out io.Writer) *cobra.Command {
s := options.NewDeschedulerServer()
cmd := &cobra.Command{
Use: "descheduler",
Short: "descheduler",
Long: `The descheduler evicts pods which may be bound to less desired nodes`,
Run: func(cmd *cobra.Command, args []string) {
logs.InitLogs()
defer logs.FlushLogs()
err := Run(s)
if err != nil {
glog.Errorf("%v", err)
}
},
}
cmd.SetOutput(out)
flags := cmd.Flags()
flags.SetNormalizeFunc(aflag.WordSepNormalizeFunc)
flags.AddGoFlagSet(flag.CommandLine)
s.AddFlags(flags)
return cmd
}
func Run(rs *options.DeschedulerServer) error {
return descheduler.Run(rs)
}

View File

@@ -1,86 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
"fmt"
"github.com/spf13/cobra"
"runtime"
"strings"
)
var (
// gitCommit is a constant representing the source version that
// generated this build. It should be set during build via -ldflags.
gitCommit string
// version is a constant representing the version tag that
// generated this build. It should be set during build via -ldflags.
version string
// buildDate in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
//It should be set during build via -ldflags.
buildDate string
)
// Info holds the information related to descheduler app version.
type Info struct {
Major string `json:"major"`
Minor string `json:"minor"`
GitCommit string `json:"gitCommit"`
GitVersion string `json:"gitVersion"`
BuildDate string `json:"buildDate"`
GoVersion string `json:"goVersion"`
Compiler string `json:"compiler"`
Platform string `json:"platform"`
}
// Get returns the overall codebase version. It's for detecting
// what code a binary was built from.
func Get() Info {
majorVersion, minorVersion := splitVersion(version)
return Info{
Major: majorVersion,
Minor: minorVersion,
GitCommit: gitCommit,
GitVersion: version,
BuildDate: buildDate,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}
}
func NewVersionCommand() *cobra.Command {
var versionCmd = &cobra.Command{
Use: "version",
Short: "Version of descheduler",
Long: `Prints the version of descheduler.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Descheduler version %+v\n", Get())
},
}
return versionCmd
}
// splitVersion splits the git version to generate major and minor versions needed.
func splitVersion(version string) (string, string) {
if version == "" {
return "", ""
}
// A sample version would be of form v0.1.0-7-ge884046, so split at first '.' and
// then return 0 and 1+(+ appended to follow semver convention) for major and minor versions.
return strings.Trim(strings.Split(version, ".")[0], "v"), strings.Split(version, ".")[1] + "+"
}

View File

@@ -1,36 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"flag"
"fmt"
"os"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app"
)
func main() {
out := os.Stdout
cmd := app.NewDeschedulerCommand(out)
cmd.AddCommand(app.NewVersionCommand())
flag.CommandLine.Parse([]string{})
if err := cmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

View File

@@ -1,3 +0,0 @@
# Kubernetes Community Code of Conduct
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)

View File

@@ -1,8 +0,0 @@
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsViolatingNodeAffinity":
enabled: true
params:
nodeAffinityType:
- "requiredDuringSchedulingIgnoredDuringExecution"

View File

@@ -1,19 +0,0 @@
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemoveDuplicates":
enabled: true
"RemovePodsViolatingInterPodAntiAffinity":
enabled: true
"LowNodeUtilization":
enabled: true
params:
nodeResourceUtilizationThresholds:
thresholds:
"cpu" : 20
"memory": 20
"pods": 20
targetThresholds:
"cpu" : 50
"memory": 50
"pods": 50

352
glide.lock generated
View File

@@ -1,352 +0,0 @@
hash: 374e925e75f6b711fd89523308d62c744e1a1846bc5923b36b864c19809eef8b
updated: 2018-01-09T00:39:38.149357059-05:00
imports:
- name: github.com/davecgh/go-spew
version: 782f4967f2dc4564575ca782fe2d04090b5faca8
subpackages:
- spew
- name: github.com/docker/distribution
version: edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
subpackages:
- digestset
- reference
- name: github.com/emicklei/go-restful
version: ff4f55a206334ef123e4f79bbf348980da81ca46
subpackages:
- log
- name: github.com/ghodss/yaml
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
- name: github.com/go-openapi/jsonpointer
version: 46af16f9f7b149af66e5d1bd010e3574dc06de98
- name: github.com/go-openapi/jsonreference
version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272
- name: github.com/go-openapi/spec
version: 7abd5745472fff5eb3685386d5fb8bf38683154d
- name: github.com/go-openapi/swag
version: f3f9494671f93fcff853e3c6e9e948b3eb71e590
- name: github.com/gogo/protobuf
version: c0656edd0d9eab7c66d1eb0c568f9039345796f7
subpackages:
- proto
- sortkeys
- name: github.com/golang/glog
version: 23def4e6c14b4da8ac2ed8007337bc5eb5007998
- name: github.com/golang/protobuf
version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9
subpackages:
- jsonpb
- proto
- ptypes
- ptypes/any
- ptypes/duration
- ptypes/struct
- ptypes/timestamp
- name: github.com/google/btree
version: 7d79101e329e5a3adf994758c578dab82b90c017
- name: github.com/google/gofuzz
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
- name: github.com/googleapis/gnostic
version: 0c5108395e2debce0d731cf0287ddf7242066aba
subpackages:
- OpenAPIv2
- compiler
- extensions
- name: github.com/gregjones/httpcache
version: 787624de3eb7bd915c329cba748687a3b22666a6
subpackages:
- diskcache
- name: github.com/hashicorp/golang-lru
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
subpackages:
- simplelru
- name: github.com/howeyc/gopass
version: bf9dde6d0d2c004a008c27aaee91170c786f6db8
- name: github.com/imdario/mergo
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
- name: github.com/inconshreveable/mousetrap
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
- name: github.com/json-iterator/go
version: 36b14963da70d11297d313183d7e6388c8510e1e
- name: github.com/juju/ratelimit
version: 5b9ff866471762aa2ab2dced63c9fb6f53921342
- name: github.com/kubernetes/repo-infra
version: dbcbd7624d5e4eb29f33c48edf1b1651809827a3
- name: github.com/mailru/easyjson
version: 2f5df55504ebc322e4d52d34df6a1f5b503bf26d
subpackages:
- buffer
- jlexer
- jwriter
- name: github.com/opencontainers/go-digest
version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
- name: github.com/peterbourgon/diskv
version: 5f041e8faa004a95c88a202771f4cc3e991971e6
- name: github.com/PuerkitoBio/purell
version: 8a290539e2e8629dbc4e6bad948158f790ec31f4
- name: github.com/PuerkitoBio/urlesc
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
- name: github.com/spf13/cobra
version: f62e98d28ab7ad31d707ba837a966378465c7b57
- name: github.com/spf13/pflag
version: 4c012f6dcd9546820e378d0bdda4d8fc772cdfea
- name: github.com/ugorji/go
version: f57d8945648dbfe4c332cff9c50fb57548958e3f
subpackages:
- codec
- name: golang.org/x/crypto
version: 81e90905daefcd6fd217b62423c0908922eadb30
subpackages:
- bcrypt
- blowfish
- nacl/secretbox
- poly1305
- salsa20/salsa
- ssh/terminal
- name: golang.org/x/net
version: 1c05540f6879653db88113bc4a2b70aec4bd491f
subpackages:
- context
- html
- html/atom
- http2
- http2/hpack
- idna
- internal/timeseries
- lex/httplex
- trace
- websocket
- name: golang.org/x/sys
version: 95c6576299259db960f6c5b9b69ea52422860fce
subpackages:
- unix
- windows
- name: golang.org/x/text
version: b19bf474d317b857955b12035d2c5acb57ce8b01
subpackages:
- cases
- internal
- internal/tag
- language
- runes
- secure/bidirule
- secure/precis
- transform
- unicode/bidi
- unicode/norm
- width
- name: golang.org/x/tools
version: 8cab8a1319f0be9798e7fe78b15da75e5f94b2e9
subpackages:
- imports
- name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/yaml.v2
version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
- name: k8s.io/api
version: af4bc157c3a209798fc897f6d4aaaaeb6c2e0d6a
subpackages:
- admissionregistration/v1alpha1
- admissionregistration/v1beta1
- apps/v1
- apps/v1beta1
- apps/v1beta2
- authentication/v1
- authentication/v1beta1
- authorization/v1
- authorization/v1beta1
- autoscaling/v1
- autoscaling/v2beta1
- batch/v1
- batch/v1beta1
- batch/v2alpha1
- certificates/v1beta1
- core/v1
- events/v1beta1
- extensions/v1beta1
- networking/v1
- policy/v1beta1
- rbac/v1
- rbac/v1alpha1
- rbac/v1beta1
- scheduling/v1alpha1
- settings/v1alpha1
- storage/v1
- storage/v1alpha1
- storage/v1beta1
- name: k8s.io/apiextensions-apiserver
version: aaccab68c17a51ccdfd3c8559221cce9334d3394
subpackages:
- pkg/features
- name: k8s.io/apimachinery
version: 180eddb345a5be3a157cea1c624700ad5bd27b8f
subpackages:
- pkg/api/errors
- pkg/api/meta
- pkg/api/resource
- pkg/apimachinery
- pkg/apimachinery/announced
- pkg/apimachinery/registered
- pkg/apis/meta/internalversion
- pkg/apis/meta/v1
- pkg/apis/meta/v1/unstructured
- pkg/apis/meta/v1alpha1
- pkg/conversion
- pkg/conversion/queryparams
- pkg/fields
- pkg/labels
- pkg/runtime
- pkg/runtime/schema
- pkg/runtime/serializer
- pkg/runtime/serializer/json
- pkg/runtime/serializer/protobuf
- pkg/runtime/serializer/recognizer
- pkg/runtime/serializer/streaming
- pkg/runtime/serializer/versioning
- pkg/selection
- pkg/types
- pkg/util/cache
- pkg/util/clock
- pkg/util/diff
- pkg/util/errors
- pkg/util/framer
- pkg/util/intstr
- pkg/util/json
- pkg/util/net
- pkg/util/runtime
- pkg/util/sets
- pkg/util/validation
- pkg/util/validation/field
- pkg/util/wait
- pkg/util/yaml
- pkg/version
- pkg/watch
- third_party/forked/golang/reflect
- name: k8s.io/apiserver
version: 91e14f394e4796abf5a994a349a222e7081d86b6
subpackages:
- pkg/features
- pkg/util/feature
- pkg/util/flag
- pkg/util/logs
- name: k8s.io/client-go
version: 78700dec6369ba22221b72770783300f143df150
subpackages:
- discovery
- discovery/fake
- kubernetes
- kubernetes/fake
- kubernetes/scheme
- kubernetes/typed/admissionregistration/v1alpha1
- kubernetes/typed/admissionregistration/v1alpha1/fake
- kubernetes/typed/admissionregistration/v1beta1
- kubernetes/typed/admissionregistration/v1beta1/fake
- kubernetes/typed/apps/v1
- kubernetes/typed/apps/v1/fake
- kubernetes/typed/apps/v1beta1
- kubernetes/typed/apps/v1beta1/fake
- kubernetes/typed/apps/v1beta2
- kubernetes/typed/apps/v1beta2/fake
- kubernetes/typed/authentication/v1
- kubernetes/typed/authentication/v1/fake
- kubernetes/typed/authentication/v1beta1
- kubernetes/typed/authentication/v1beta1/fake
- kubernetes/typed/authorization/v1
- kubernetes/typed/authorization/v1/fake
- kubernetes/typed/authorization/v1beta1
- kubernetes/typed/authorization/v1beta1/fake
- kubernetes/typed/autoscaling/v1
- kubernetes/typed/autoscaling/v1/fake
- kubernetes/typed/autoscaling/v2beta1
- kubernetes/typed/autoscaling/v2beta1/fake
- kubernetes/typed/batch/v1
- kubernetes/typed/batch/v1/fake
- kubernetes/typed/batch/v1beta1
- kubernetes/typed/batch/v1beta1/fake
- kubernetes/typed/batch/v2alpha1
- kubernetes/typed/batch/v2alpha1/fake
- kubernetes/typed/certificates/v1beta1
- kubernetes/typed/certificates/v1beta1/fake
- kubernetes/typed/core/v1
- kubernetes/typed/core/v1/fake
- kubernetes/typed/events/v1beta1
- kubernetes/typed/events/v1beta1/fake
- kubernetes/typed/extensions/v1beta1
- kubernetes/typed/extensions/v1beta1/fake
- kubernetes/typed/networking/v1
- kubernetes/typed/networking/v1/fake
- kubernetes/typed/policy/v1beta1
- kubernetes/typed/policy/v1beta1/fake
- kubernetes/typed/rbac/v1
- kubernetes/typed/rbac/v1/fake
- kubernetes/typed/rbac/v1alpha1
- kubernetes/typed/rbac/v1alpha1/fake
- kubernetes/typed/rbac/v1beta1
- kubernetes/typed/rbac/v1beta1/fake
- kubernetes/typed/scheduling/v1alpha1
- kubernetes/typed/scheduling/v1alpha1/fake
- kubernetes/typed/settings/v1alpha1
- kubernetes/typed/settings/v1alpha1/fake
- kubernetes/typed/storage/v1
- kubernetes/typed/storage/v1/fake
- kubernetes/typed/storage/v1alpha1
- kubernetes/typed/storage/v1alpha1/fake
- kubernetes/typed/storage/v1beta1
- kubernetes/typed/storage/v1beta1/fake
- listers/core/v1
- pkg/version
- rest
- rest/watch
- testing
- tools/auth
- tools/cache
- tools/clientcmd
- tools/clientcmd/api
- tools/clientcmd/api/latest
- tools/clientcmd/api/v1
- tools/metrics
- tools/pager
- tools/reference
- transport
- util/buffer
- util/cert
- util/flowcontrol
- util/homedir
- util/integer
- name: k8s.io/code-generator
version: fef8bcdbaf36ac6a1a18c9ef7d85200b249fad30
- name: k8s.io/gengo
version: 1ef560bbde5195c01629039ad3b337ce63e7b321
- name: k8s.io/kube-openapi
version: 39a7bf85c140f972372c2a0d1ee40adbf0c8bfe1
subpackages:
- pkg/builder
- pkg/common
- pkg/handler
- pkg/util
- pkg/util/proto
- name: k8s.io/kubernetes
version: 925c127ec6b946659ad0fd596fa959be43f0cc05
subpackages:
- pkg/api/legacyscheme
- pkg/api/v1
- pkg/api/v1/resource
- pkg/apis/autoscaling
- pkg/apis/core
- pkg/apis/core/helper
- pkg/apis/core/helper/qos
- pkg/apis/core/install
- pkg/apis/core/v1
- pkg/apis/core/v1/helper
- pkg/apis/extensions
- pkg/apis/networking
- pkg/apis/policy
- pkg/apis/policy/v1beta1
- pkg/apis/scheduling
- pkg/features
- pkg/kubelet/types
- pkg/util/parsers
- pkg/util/pointer
- plugin/pkg/scheduler/algorithm/priorities/util
- plugin/pkg/scheduler/schedulercache
- plugin/pkg/scheduler/util
testImports: []

View File

@@ -1,23 +0,0 @@
package: github.com/kubernetes-incubator/descheduler
import:
- package: k8s.io/client-go
version: 78700dec6369ba22221b72770783300f143df150
- package: k8s.io/api
version: af4bc157c3a209798fc897f6d4aaaaeb6c2e0d6a
- package: k8s.io/apiserver
version: 91e14f394e4796abf5a994a349a222e7081d86b6
- package: k8s.io/apimachinery
version: 180eddb345a5be3a157cea1c624700ad5bd27b8f
- package: k8s.io/kubernetes
version: v1.9.0
- package: k8s.io/code-generator
version: kubernetes-1.9.0
- package: github.com/kubernetes/repo-infra
- package: github.com/spf13/cobra
version: f62e98d28ab7ad31d707ba837a966378465c7b57
- package: k8s.io/gengo
- package: github.com/ugorji/go
version: v.1.1-beta
- package: golang.org/x/tools
subpackages:
- imports

View File

@@ -1,16 +0,0 @@
/*
Copyright YEAR The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

View File

@@ -1,95 +0,0 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail
echo "Make sure that uuid package is installed"
master_uuid=$(uuid)
node1_uuid=$(uuid)
node2_uuid=$(uuid)
kube_apiserver_port=6443
kube_version=1.9.4
DESCHEDULER_ROOT=$(dirname "${BASH_SOURCE}")/../../
E2E_GCE_HOME=$DESCHEDULER_ROOT/hack/e2e-gce
create_cluster() {
echo "#################### Creating instances ##########################"
gcloud compute instances create descheduler-$master_uuid --image="ubuntu-1604-xenial-v20180306" --image-project="ubuntu-os-cloud" --zone=us-east1-b
# Keeping the --zone here so as to make sure that e2e's can run locally.
echo "gcloud compute instances delete descheduler-$master_uuid --zone=us-east1-b --quiet" > $E2E_GCE_HOME/delete_cluster.sh
gcloud compute instances create descheduler-$node1_uuid --image="ubuntu-1604-xenial-v20180306" --image-project="ubuntu-os-cloud" --zone=us-east1-b
echo "gcloud compute instances delete descheduler-$node1_uuid --zone=us-east1-b --quiet" >> $E2E_GCE_HOME/delete_cluster.sh
gcloud compute instances create descheduler-$node2_uuid --image="ubuntu-1604-xenial-v20180306" --image-project="ubuntu-os-cloud" --zone=us-east1-b
echo "gcloud compute instances delete descheduler-$node2_uuid --zone=us-east1-b --quiet" >> $E2E_GCE_HOME/delete_cluster.sh
# Delete the firewall port created for master.
echo "gcloud compute firewall-rules delete kubeapiserver-$master_uuid --quiet" >> $E2E_GCE_HOME/delete_cluster.sh
chmod 755 $E2E_GCE_HOME/delete_cluster.sh
}
generate_kubeadm_instance_files() {
# TODO: Check if they have come up. awk $6 contains the state(RUNNING or not).
master_public_ip=$(gcloud compute instances list | grep $master_uuid|awk '{print $5}')
node1_public_ip=$(gcloud compute instances list | grep $node1_uuid|awk '{print $5}')
node2_public_ip=$(gcloud compute instances list | grep $node2_uuid|awk '{print $5}')
echo "kubeadm init --kubernetes-version=${kube_version} --apiserver-advertise-address=${master_public_ip}" --skip-preflight-checks --pod-network-cidr=10.96.0.0/12 > $E2E_GCE_HOME/kubeadm_install.sh
}
transfer_install_files() {
gcloud compute scp $E2E_GCE_HOME/kubeadm_preinstall.sh descheduler-$master_uuid:/tmp --zone=us-east1-b
gcloud compute scp $E2E_GCE_HOME/kubeadm_install.sh descheduler-$master_uuid:/tmp --zone=us-east1-b
gcloud compute scp $E2E_GCE_HOME/kubeadm_preinstall.sh descheduler-$node1_uuid:/tmp --zone=us-east1-b
gcloud compute scp $E2E_GCE_HOME/kubeadm_preinstall.sh descheduler-$node2_uuid:/tmp --zone=us-east1-b
}
install_kube() {
# Docker installation.
gcloud compute ssh descheduler-$master_uuid --command "sudo apt-get update; sudo apt-get install -y docker.io" --zone=us-east1-b
gcloud compute ssh descheduler-$node1_uuid --command "sudo apt-get update; sudo apt-get install -y docker.io" --zone=us-east1-b
gcloud compute ssh descheduler-$node2_uuid --command "sudo apt-get update; sudo apt-get install -y docker.io" --zone=us-east1-b
# kubeadm installation.
# 1. Transfer files to master, nodes.
transfer_install_files
# 2. Install kubeadm.
#TODO: Add rm /tmp/kubeadm_install.sh
# Open port for kube API server
gcloud compute firewall-rules create kubeapiserver-$master_uuid --allow tcp:6443 --source-tags=descheduler-$master_uuid --source-ranges=0.0.0.0/0 --description="Opening api server port"
gcloud compute ssh descheduler-$master_uuid --command "sudo chmod 755 /tmp/kubeadm_preinstall.sh; sudo /tmp/kubeadm_preinstall.sh" --zone=us-east1-b
kubeadm_join_command=$(gcloud compute ssh descheduler-$master_uuid --command "sudo chmod 755 /tmp/kubeadm_install.sh; sudo /tmp/kubeadm_install.sh" --zone=us-east1-b|grep 'kubeadm join')
# Copy the kubeconfig file onto /tmp for e2e tests.
gcloud compute ssh descheduler-$master_uuid --command "sudo cp /etc/kubernetes/admin.conf /tmp; sudo chmod 777 /tmp/admin.conf" --zone=us-east1-b
gcloud compute scp descheduler-$master_uuid:/tmp/admin.conf /tmp/admin.conf --zone=us-east1-b
# Postinstall on master, need to add a network plugin for kube-dns to come to running state.
gcloud compute ssh descheduler-$master_uuid --command "sudo kubectl apply -f https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter.yaml --kubeconfig /etc/kubernetes/admin.conf" --zone=us-east1-b
echo $kubeadm_join_command > $E2E_GCE_HOME/kubeadm_join.sh
# Copy kubeadm_join to every node.
#TODO: Put these in a loop, so that extension becomes possible.
gcloud compute ssh descheduler-$node1_uuid --command "sudo chmod 755 /tmp/kubeadm_preinstall.sh; sudo /tmp/kubeadm_preinstall.sh" --zone=us-east1-b
gcloud compute scp $E2E_GCE_HOME/kubeadm_join.sh descheduler-$node1_uuid:/tmp --zone=us-east1-b
gcloud compute ssh descheduler-$node1_uuid --command "sudo chmod 755 /tmp/kubeadm_join.sh; sudo /tmp/kubeadm_join.sh" --zone=us-east1-b
gcloud compute ssh descheduler-$node2_uuid --command "sudo chmod 755 /tmp/kubeadm_preinstall.sh; sudo /tmp/kubeadm_preinstall.sh" --zone=us-east1-b
gcloud compute scp $E2E_GCE_HOME/kubeadm_join.sh descheduler-$node2_uuid:/tmp --zone=us-east1-b
gcloud compute ssh descheduler-$node2_uuid --command "sudo chmod 755 /tmp/kubeadm_join.sh; sudo /tmp/kubeadm_join.sh" --zone=us-east1-b
}
create_cluster
generate_kubeadm_instance_files
install_kube

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -e
gcloud auth activate-service-account --key-file "${GCE_SA_CREDS}"
gcloud config set project $GCE_PROJECT_ID
gcloud config set compute/zone $GCE_ZONE

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
set -e
wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-176.0.0-linux-x86_64.tar.gz
tar -xvzf google-cloud-sdk-176.0.0-linux-x86_64.tar.gz
./google-cloud-sdk/install.sh -q

View File

@@ -1,11 +0,0 @@
apt-get update
apt-get install -y docker.io
apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
exit 0

View File

@@ -1,47 +0,0 @@
#!/bin/bash
# Copyright 2014 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
# os::util::absolute_path returns the absolute path to the directory provided
function os::util::absolute_path() {
local relative_path="$1"
local absolute_path
pushd "${relative_path}" >/dev/null
relative_path="$( pwd )"
if [[ -h "${relative_path}" ]]; then
absolute_path="$( readlink "${relative_path}" )"
else
absolute_path="${relative_path}"
fi
popd >/dev/null
echo "${absolute_path}"
}
readonly -f os::util::absolute_path
# find the absolute path to the root of the Origin source tree
init_source="$( dirname "${BASH_SOURCE}" )/../.."
OS_ROOT="$( os::util::absolute_path "${init_source}" )"
export OS_ROOT
cd "${OS_ROOT}"
PRJ_PREFIX="github.com/${REPO_ORG:-kubernetes-incubator}/descheduler"
OS_OUTPUT_BINPATH="${OS_ROOT}/_output/bin"

View File

@@ -1,151 +0,0 @@
#!/bin/bash
# Copyright 2015 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
# The sort at the end makes sure we feed the topological sort a deterministic
# list (since there aren't many dependencies).
generated_files=($(
find . -not \( \
\( \
-wholename './output' \
-o -wholename './_output' \
-o -wholename './staging' \
-o -wholename './release' \
-o -wholename './target' \
-o -wholename '*/third_party/*' \
-o -wholename '*/vendor/*' \
-o -wholename '*/codecgen-*-1234.generated.go' \
\) -prune \
\) -name '*.generated.go' | LC_ALL=C sort -r
))
# We only work for deps within this prefix.
#my_prefix="k8s.io/kubernetes"
my_prefix="github.com/${REPO_ORG:-kubernetes-incubator}/descheduler"
# Register function to be called on EXIT to remove codecgen
# binary and also to touch the files that should be regenerated
# since they are first removed.
# This is necessary to make the script work after previous failure.
function cleanup {
rm -f "${CODECGEN:-}"
pushd "${KUBE_ROOT}" > /dev/null
for (( i=0; i < number; i++ )); do
touch "${generated_files[${i}]}" || true
done
popd > /dev/null
}
trap cleanup EXIT
# Precompute dependencies for all directories.
# Then sort all files in the dependency order.
number=${#generated_files[@]}
result=""
for (( i=0; i<number; i++ )); do
visited[${i}]=false
file="${generated_files[${i}]/\.generated\.go/.go}"
deps[${i}]=$(go list -f '{{range .Deps}}{{.}}{{"\n"}}{{end}}' ${file} | grep "^${my_prefix}")
done
###echo "DBG: found $number generated files"
###for f in $(echo "${generated_files[@]}" | LC_ALL=C sort); do
### echo "DBG: $f"
###done
# NOTE: depends function assumes that the whole repository is under
# $my_prefix - it will NOT work if that is not true.
function depends {
rhs="$(dirname ${generated_files[$2]/#./${my_prefix}})"
###echo "DBG: does ${file} depend on ${rhs}?"
for dep in ${deps[$1]}; do
###echo "DBG: checking against $dep"
if [[ "${dep}" == "${rhs}" ]]; then
###echo "DBG: = yes"
return 0
fi
done
###echo "DBG: = no"
return 1
}
function tsort {
visited[$1]=true
local j=0
for (( j=0; j<number; j++ )); do
if ! ${visited[${j}]}; then
if depends "$1" ${j}; then
tsort $j
fi
fi
done
result="${result} $1"
}
echo "Building dependencies"
for (( i=0; i<number; i++ )); do
###echo "DBG: considering ${generated_files[${i}]}"
if ! ${visited[${i}]}; then
###echo "DBG: tsorting ${generated_files[${i}]}"
tsort ${i}
fi
done
index=(${result})
haveindex=${index:-}
if [[ -z ${haveindex} ]]; then
echo No files found for $0
echo A previous run of $0 may have deleted all the files and then crashed.
echo Use 'touch' to create files named 'types.generated.go' listed as deleted in 'git status'
exit 1
fi
echo "Building codecgen"
CODECGEN="${PWD}/codecgen_binary"
go build -o "${CODECGEN}" ./vendor/github.com/ugorji/go/codec/codecgen
# Running codecgen fails if some of the files doesn't compile.
# Thus (since all the files are completely auto-generated and
# not required for the code to be compilable, we first remove
# them and the regenerate them.
for (( i=0; i < number; i++ )); do
rm -f "${generated_files[${i}]}"
done
# Generate files in the dependency order.
for current in "${index[@]}"; do
generated_file=${generated_files[${current}]}
initial_dir=${PWD}
file=${generated_file/\.generated\.go/.go}
echo "processing ${file}"
# codecgen work only if invoked from directory where the file
# is located.
pushd "$(dirname ${file})" > /dev/null
base_file=$(basename "${file}")
base_generated_file=$(basename "${generated_file}")
# We use '-d 1234' flag to have a deterministic output every time.
# The constant was just randomly chosen.
###echo "DBG: running ${CODECGEN} -d 1234 -o ${base_generated_file} ${base_file}"
${CODECGEN} -d 1234 -o "${base_generated_file}" "${base_file}"
# Add boilerplate at the beginning of the generated file.
sed 's/YEAR/2017/' "${initial_dir}/hack/boilerplate/boilerplate.go.txt" > "${base_generated_file}.tmp"
cat "${base_generated_file}" >> "${base_generated_file}.tmp"
mv "${base_generated_file}.tmp" "${base_generated_file}"
popd > /dev/null
done

View File

@@ -1,9 +0,0 @@
#!/bin/bash
source "$(dirname "${BASH_SOURCE}")/lib/init.sh"
go build -o "${OS_OUTPUT_BINPATH}/conversion-gen" "${PRJ_PREFIX}/vendor/k8s.io/code-generator/cmd/conversion-gen"
${OS_OUTPUT_BINPATH}/conversion-gen \
--go-header-file "hack/boilerplate/boilerplate.go.txt" \
--input-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api/v1alpha1" \
--output-file-base zz_generated.conversion

View File

@@ -1,10 +0,0 @@
#!/bin/bash
source "$(dirname "${BASH_SOURCE}")/lib/init.sh"
go build -o "${OS_OUTPUT_BINPATH}/deepcopy-gen" "${PRJ_PREFIX}/vendor/k8s.io/code-generator/cmd/deepcopy-gen"
${OS_OUTPUT_BINPATH}/deepcopy-gen \
--go-header-file "hack/boilerplate/boilerplate.go.txt" \
--input-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig,${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api,${PRJ_PREFIX}/pkg/api/v1alpha1" \
--output-file-base zz_generated.deepcopy

View File

@@ -1,10 +0,0 @@
#!/bin/bash
source "$(dirname "${BASH_SOURCE}")/lib/init.sh"
go build -o "${OS_OUTPUT_BINPATH}/defaulter-gen" "${PRJ_PREFIX}/vendor/k8s.io/code-generator/cmd/defaulter-gen"
${OS_OUTPUT_BINPATH}/defaulter-gen \
--go-header-file "hack/boilerplate/boilerplate.go.txt" \
--input-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api/v1alpha1" \
--extra-peer-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api/v1alpha1" \
--output-file-base zz_generated.defaults

View File

@@ -1,54 +0,0 @@
#!/bin/bash
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
DESCHEDULER_ROOT=$(dirname "${BASH_SOURCE}")/..
GO_VERSION=($(go version))
if [[ -z $(echo "${GO_VERSION[2]}" | grep -E 'go1.2|go1.3|go1.4|go1.5|go1.6|go1.7|go1.8|go1.9') ]]; then
echo "Unknown go version '${GO_VERSION}', skipping gofmt."
exit 1
fi
cd "${DESCHEDULER_ROOT}"
find_files() {
find . -not \( \
\( \
-wholename './output' \
-o -wholename './_output' \
-o -wholename './release' \
-o -wholename './target' \
-o -wholename './.git' \
-o -wholename '*/third_party/*' \
-o -wholename '*/Godeps/*' \
-o -wholename '*/vendor/*' \
\) -prune \
\) -name '*.go'
}
GOFMT="gofmt -s"
bad_files=$(find_files | xargs $GOFMT -l)
if [[ -n "${bad_files}" ]]; then
echo "!!! '$GOFMT' needs to be run on the following files: "
echo "${bad_files}"
exit 1
fi

762
index.yaml Normal file
View File

@@ -0,0 +1,762 @@
apiVersion: v1
entries:
descheduler:
- apiVersion: v1
appVersion: 0.34.0
created: "2025-10-30T16:41:34.519386946Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 0fb91a600418400c8581eae65adab602ff2589104540306e5c6936a50fdd5bd6
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: sig-scheduling@kubernetes.io
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.34.0/descheduler-0.34.0.tgz
version: 0.34.0
- apiVersion: v1
appVersion: 0.33.0
created: "2025-05-04T19:49:46.589102937Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 1f32da32dedc6c066f197637e1fbd10546e9c6987322b88e71add1c9765c978f
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: sig-scheduling@kubernetes.io
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.33.0/descheduler-0.33.0.tgz
version: 0.33.0
- apiVersion: v1
appVersion: 0.32.2
created: "2025-02-11T04:46:21.248724497Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 011205c924597543fe93bf6ce66d75a33bc6a7d1a029eedd4c0390a16e57e264
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.32.2/descheduler-0.32.2.tgz
version: 0.32.2
- apiVersion: v1
appVersion: 0.32.1
created: "2025-01-06T23:08:49.134597641Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: e104f5e14b8ef7f5166912e1e9a61785977f5f17ca95c43e744d0685528f8436
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.32.1/descheduler-0.32.1.tgz
version: 0.32.1
- apiVersion: v1
appVersion: 0.32.0
created: "2025-01-02T23:34:02.843431016Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 4ca12ecc4916ae1c47ae9b03571e371766e6b6846cc1821299bbd2da75042bb3
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.32.0/descheduler-0.32.0.tgz
version: 0.32.0
- apiVersion: v1
appVersion: 0.31.0
created: "2024-09-09T22:59:21.130329884Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 7e9d95713e2384b0976e6ea89742550c83c9adf52005e9c0cc9da3f04477d530
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.31.0/descheduler-0.31.0.tgz
version: 0.31.0
- apiVersion: v1
appVersion: 0.30.2
created: "2024-11-20T15:09:49.215945303Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 7608d3966b7d1fc08fe31cdffc283dc2a4d7a473fe63efa1672a5926b81774c2
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.30.2/descheduler-0.30.2.tgz
version: 0.30.2
- apiVersion: v1
appVersion: 0.30.1
created: "2024-06-05T12:06:23.870221344Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 8ab41d27011119ff62abfb86fa9253d66a1c74b7247d32c5786a96d3fd11abd2
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.30.1/descheduler-0.30.1.tgz
version: 0.30.1
- apiVersion: v1
appVersion: 0.30.0
created: "2024-05-20T14:03:13.843460018Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 7599edc8d0c09821e290438a850509d762a6ad79d48024ab5c9ec56e70cc4229
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.30.0/descheduler-0.30.0.tgz
version: 0.30.0
- apiVersion: v1
appVersion: 0.29.0
created: "2024-01-02T18:54:20.992594156Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: f6157f5d02bf90e8f84e74a8d7ccb1660b802d4aa710fdb32d9398eaccd50f67
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.29.0/descheduler-0.29.0.tgz
version: 0.29.0
- apiVersion: v1
appVersion: 0.28.1
created: "2023-11-29T17:22:04.773831615Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 33ccfc268727e9b129254bc450c192d3084d56967ceb315e4a1d6d744bc204ea
home: https://github.com/kubernetes-sigs/descheduler
icon: https://raw.githubusercontent.com/kubernetes-sigs/descheduler/master/assets/logo/descheduler-stacked-color.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.28.1/descheduler-0.28.1.tgz
version: 0.28.1
- apiVersion: v1
appVersion: 0.28.0
created: "2023-08-24T13:07:51.303386087Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 50efd424df52a1bfd6e40900e634394e66db4a901ff797b595481855dcb01584
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.28.0/descheduler-0.28.0.tgz
version: 0.28.0
- apiVersion: v1
appVersion: 0.27.1
created: "2023-05-31T08:18:14.881530101Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: c7d93a7fc65f8311bd1853893bd4c5b3f3f4dabcf182c896846752d99720c98b
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.27.1/descheduler-0.27.1.tgz
version: 0.27.1
- apiVersion: v1
appVersion: 0.27.0
created: "2023-05-05T14:14:44.725587487Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: dd06be2789590c070b204e0f7f0910ec111d90a13e8b5a46e3b80b015e458b11
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.27.0/descheduler-0.27.0.tgz
version: 0.27.0
- apiVersion: v1
appVersion: 0.26.1
created: "2023-04-04T17:34:17.284123888Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 391167e6741cc412bc12bc0e5a6ab513a63528fa4d161396e2c14f017eb1b7b3
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.26.1/descheduler-0.26.1.tgz
version: 0.26.1
- apiVersion: v1
appVersion: 0.26.0
created: "2023-01-17T14:42:00.271072093Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 4bb1285dcb65814059b13d268d0f230a0993527fddc652a0b82a2039aed7a1b4
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.26.0/descheduler-0.26.0.tgz
version: 0.26.0
- apiVersion: v1
appVersion: 0.25.1
created: "2022-10-17T21:53:53.644159593Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 68b973e5294bcc1735ec7cfb9c82769c4dccc4a2ef75d8cf2a3244ebaaa73b5d
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.25.2/descheduler-0.25.2.tgz
version: 0.25.2
- apiVersion: v1
appVersion: 0.25.1
created: "2022-09-27T15:02:20.445257034Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 758d970bf9fc7d575f3a171affd3a60475dafba6405cfcfd98d42062582a75ec
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.25.1/descheduler-0.25.1.tgz
version: 0.25.1
- apiVersion: v1
appVersion: 0.25.0
created: "2022-09-15T16:33:37.881987127Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 8aa3f1af4a9f3ab49dd9c177c88596993d1a1481b83318ebeff3a49e49714bdd
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.25.0/descheduler-0.25.0.tgz
version: 0.25.0
- apiVersion: v1
appVersion: 0.24.1
created: "2022-05-31T13:39:20.603755914Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 3cec16a47c2416e5f5946eae473ce7fd073dfeb2ca49fa87e900886c57707fcf
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.24.1/descheduler-0.24.1.tgz
version: 0.24.1
- apiVersion: v1
appVersion: 0.24.0
created: "2022-05-23T14:14:10.037216155Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 2cd39048ebca1bf37d99be4f659364bedaa5c6e6cfb62640914e327884945b24
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.24.0/descheduler-0.24.0.tgz
version: 0.24.0
- apiVersion: v1
appVersion: 0.23.1
created: "2022-02-28T18:56:10.944563703Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 7c6c08ca5d1a0be8632e3596d721f5fc99117e3a422642cb908f5a2d2e355059
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.23.2/descheduler-0.23.2.tgz
version: 0.23.2
- apiVersion: v1
appVersion: 0.23.0
created: "2022-02-09T13:34:50.093591254Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: a862faecae9eae025558d69716ebd67e467cc0316a431487d9f64dd8a60b7848
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.23.1/descheduler-0.23.1.tgz
version: 0.23.1
- apiVersion: v1
appVersion: 0.23.0
created: "2022-02-03T20:23:32.21492446Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 224b16599938ee331612c01dd5889a88a3ed3ef1872a9e108621aba3fb608713
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.23.0/descheduler-0.23.0.tgz
version: 0.23.0
- apiVersion: v1
appVersion: 0.22.1
created: "2021-09-29T16:37:16.381510827Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 83a407bbf981c300b6c75df148045be56797517cfcf7b744dfe8cbd3aa946c56
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.22.1/descheduler-0.22.1.tgz
version: 0.22.1
- apiVersion: v1
appVersion: 0.22.0
created: "2021-09-08T20:44:21.974382529Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 9dd645e058c66eba711acd604026dbbb546ccd5366253464bcea38d63c51ed69
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.22.0/descheduler-0.22.0.tgz
version: 0.22.0
- apiVersion: v1
appVersion: 0.21.0
created: "2021-06-08T17:43:48.212056769Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: bb951c9c5e2c76855e0bb1a3a20c5238963acd515d7c250e3b27ccefa002bec2
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.21.0/descheduler-0.21.0.tgz
version: 0.21.0
- apiVersion: v1
appVersion: 0.20.0
created: "2020-12-10T15:23:17.367104788Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: f8f0177966994e3cdb61385069ebba3f8f658107ab800a382b30d5fe809789d0
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.20.0/descheduler-0.20.0.tgz
version: 0.20.0
- apiVersion: v1
appVersion: 0.19.0
created: "2020-12-09T01:47:49.250755956Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 1331ce7da686311e18e552edd8353786694049a747ccab6616362e892579e766
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.19.2/descheduler-0.19.2.tgz
version: 0.19.2
- apiVersion: v1
appVersion: 0.18.0
created: "2020-12-08T19:34:02.786640856Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: 55b8b8e015bfa3d0794ca1d7316b2b412211fa6ccbd7649a80f7a1d6ec097f26
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.18.2/descheduler-0.18.2.tgz
version: 0.18.2
descheduler-helm-chart:
- apiVersion: v1
appVersion: 0.19.0
created: "2020-12-08T19:22:08.294224978Z"
deprecated: true
description: DEPRECATED - Descheduler for Kubernetes is used to rebalance clusters
by evicting pods that can potentially be scheduled on better nodes. In the current
implementation, descheduler does not schedule replacement of evicted pods but
relies on the default scheduler for that.
digest: b77ac9bb15ec71f7006d7d4faefffbb29b0cbcdabbef6389c858690beb12e529
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
name: descheduler-helm-chart
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.19.1/descheduler-helm-chart-0.19.1.tgz
version: 0.19.1
- apiVersion: v1
appVersion: 0.19.0
created: "2020-09-01T16:59:22.515242595Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: dc70fc1ac8b57872e54c3406000617d4cbd0b2a9653abf0054c345c471b4be1c
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: kubernetes-sig-scheduling@googlegroups.com
name: Kubernetes SIG Scheduling
name: descheduler-helm-chart
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.19.0/descheduler-helm-chart-0.19.0.tgz
version: 0.19.0
- apiVersion: v1
appVersion: 0.18.0
created: "2020-07-23T18:29:32.622241657Z"
description: Descheduler for Kubernetes is used to rebalance clusters by evicting
pods that can potentially be scheduled on better nodes. In the current implementation,
descheduler does not schedule replacement of evicted pods but relies on the
default scheduler for that.
digest: d2a7516d4b2bbd288d5016b935d1a0ce4db9cc40c4f8a6981fe5075d71f4bcda
home: https://github.com/kubernetes-sigs/descheduler
icon: https://kubernetes.io/images/favicon.png
keywords:
- kubernetes
- descheduler
- kube-scheduler
maintainers:
- email: steve.hipwell@github.com
name: stevehipwell
name: descheduler-helm-chart
sources:
- https://github.com/kubernetes-sigs/descheduler
urls:
- https://github.com/kubernetes-sigs/descheduler/releases/download/descheduler-helm-chart-0.18.1/descheduler-helm-chart-0.18.1.tgz
version: 0.18.1
generated: "2025-10-30T16:41:34.519616538Z"

View File

@@ -1,19 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package,register
package api // import "github.com/kubernetes-incubator/descheduler/pkg/api"

View File

@@ -1,48 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package install installs the descheduler's policy API group.
package install
import (
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
deschedulerapi "github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/pkg/api/v1alpha1"
deschedulerscheme "github.com/kubernetes-incubator/descheduler/pkg/descheduler/scheme"
)
func init() {
Install(deschedulerscheme.GroupFactoryRegistry, deschedulerscheme.Registry, deschedulerscheme.Scheme)
}
// Install registers the API group and adds types to a scheme
func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{
GroupName: deschedulerapi.GroupName,
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version},
AddInternalObjectsToScheme: deschedulerapi.AddToScheme,
},
announced.VersionToSchemeFunc{
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
},
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
panic(err)
}
}

View File

@@ -1,50 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// GroupName is the group name use in this package
const GroupName = "descheduler"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&DeschedulerPolicy{},
)
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DeschedulerPolicy struct {
metav1.TypeMeta
// Strategies
Strategies StrategyList
}
type StrategyName string
type StrategyList map[StrategyName]DeschedulerStrategy
type DeschedulerStrategy struct {
// Enabled or disabled
Enabled bool
// Weight
Weight int
// Strategy parameters
Params StrategyParameters
}
// Only one of its members may be specified
type StrategyParameters struct {
NodeResourceUtilizationThresholds NodeResourceUtilizationThresholds
NodeAffinityType []string
}
type Percentage float64
type ResourceThresholds map[v1.ResourceName]Percentage
type NodeResourceUtilizationThresholds struct {
Thresholds ResourceThresholds
TargetThresholds ResourceThresholds
NumberOfNodes int
}

View File

@@ -1,23 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import "k8s.io/apimachinery/pkg/runtime"
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}

View File

@@ -1,24 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=github.com/kubernetes-incubator/descheduler/pkg/api
// +k8s:defaulter-gen=TypeMeta
// Package v1alpha1 is the v1alpha1 version of the descheduler API
// +groupName=descheduler
package v1alpha1 // import "github.com/kubernetes-incubator/descheduler/pkg/api/v1alpha1"

View File

@@ -1,61 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
localSchemeBuilder = &SchemeBuilder
AddToScheme = SchemeBuilder.AddToScheme
)
// GroupName is the group name used in this package
const GroupName = "descheduler"
const GroupVersion = "v1alpha1"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
}
func addKnownTypes(scheme *runtime.Scheme) error {
// TODO this will get cleaned up with the scheme types are fixed
scheme.AddKnownTypes(SchemeGroupVersion,
&DeschedulerPolicy{},
)
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DeschedulerPolicy struct {
metav1.TypeMeta `json:",inline"`
// Strategies
Strategies StrategyList `json:"strategies,omitempty"`
}
type StrategyName string
type StrategyList map[StrategyName]DeschedulerStrategy
type DeschedulerStrategy struct {
// Enabled or disabled
Enabled bool `json:"enabled,omitempty"`
// Weight
Weight int `json:"weight,omitempty"`
// Strategy parameters
Params StrategyParameters `json:"params,omitempty"`
}
// Only one of its members may be specified
type StrategyParameters struct {
NodeResourceUtilizationThresholds NodeResourceUtilizationThresholds `json:"nodeResourceUtilizationThresholds,omitempty"`
NodeAffinityType []string `json:"nodeAffinityType,omitempty"`
}
type Percentage float64
type ResourceThresholds map[v1.ResourceName]Percentage
type NodeResourceUtilizationThresholds struct {
Thresholds ResourceThresholds `json:"thresholds,omitempty"`
TargetThresholds ResourceThresholds `json:"targetThresholds,omitempty"`
NumberOfNodes int `json:"numberOfNodes,omitempty"`
}

View File

@@ -1,146 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
package v1alpha1
import (
unsafe "unsafe"
api "github.com/kubernetes-incubator/descheduler/pkg/api"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_DeschedulerPolicy_To_api_DeschedulerPolicy,
Convert_api_DeschedulerPolicy_To_v1alpha1_DeschedulerPolicy,
Convert_v1alpha1_DeschedulerStrategy_To_api_DeschedulerStrategy,
Convert_api_DeschedulerStrategy_To_v1alpha1_DeschedulerStrategy,
Convert_v1alpha1_NodeResourceUtilizationThresholds_To_api_NodeResourceUtilizationThresholds,
Convert_api_NodeResourceUtilizationThresholds_To_v1alpha1_NodeResourceUtilizationThresholds,
Convert_v1alpha1_StrategyParameters_To_api_StrategyParameters,
Convert_api_StrategyParameters_To_v1alpha1_StrategyParameters,
)
}
func autoConvert_v1alpha1_DeschedulerPolicy_To_api_DeschedulerPolicy(in *DeschedulerPolicy, out *api.DeschedulerPolicy, s conversion.Scope) error {
out.Strategies = *(*api.StrategyList)(unsafe.Pointer(&in.Strategies))
return nil
}
// Convert_v1alpha1_DeschedulerPolicy_To_api_DeschedulerPolicy is an autogenerated conversion function.
func Convert_v1alpha1_DeschedulerPolicy_To_api_DeschedulerPolicy(in *DeschedulerPolicy, out *api.DeschedulerPolicy, s conversion.Scope) error {
return autoConvert_v1alpha1_DeschedulerPolicy_To_api_DeschedulerPolicy(in, out, s)
}
func autoConvert_api_DeschedulerPolicy_To_v1alpha1_DeschedulerPolicy(in *api.DeschedulerPolicy, out *DeschedulerPolicy, s conversion.Scope) error {
out.Strategies = *(*StrategyList)(unsafe.Pointer(&in.Strategies))
return nil
}
// Convert_api_DeschedulerPolicy_To_v1alpha1_DeschedulerPolicy is an autogenerated conversion function.
func Convert_api_DeschedulerPolicy_To_v1alpha1_DeschedulerPolicy(in *api.DeschedulerPolicy, out *DeschedulerPolicy, s conversion.Scope) error {
return autoConvert_api_DeschedulerPolicy_To_v1alpha1_DeschedulerPolicy(in, out, s)
}
func autoConvert_v1alpha1_DeschedulerStrategy_To_api_DeschedulerStrategy(in *DeschedulerStrategy, out *api.DeschedulerStrategy, s conversion.Scope) error {
out.Enabled = in.Enabled
out.Weight = in.Weight
if err := Convert_v1alpha1_StrategyParameters_To_api_StrategyParameters(&in.Params, &out.Params, s); err != nil {
return err
}
return nil
}
// Convert_v1alpha1_DeschedulerStrategy_To_api_DeschedulerStrategy is an autogenerated conversion function.
func Convert_v1alpha1_DeschedulerStrategy_To_api_DeschedulerStrategy(in *DeschedulerStrategy, out *api.DeschedulerStrategy, s conversion.Scope) error {
return autoConvert_v1alpha1_DeschedulerStrategy_To_api_DeschedulerStrategy(in, out, s)
}
func autoConvert_api_DeschedulerStrategy_To_v1alpha1_DeschedulerStrategy(in *api.DeschedulerStrategy, out *DeschedulerStrategy, s conversion.Scope) error {
out.Enabled = in.Enabled
out.Weight = in.Weight
if err := Convert_api_StrategyParameters_To_v1alpha1_StrategyParameters(&in.Params, &out.Params, s); err != nil {
return err
}
return nil
}
// Convert_api_DeschedulerStrategy_To_v1alpha1_DeschedulerStrategy is an autogenerated conversion function.
func Convert_api_DeschedulerStrategy_To_v1alpha1_DeschedulerStrategy(in *api.DeschedulerStrategy, out *DeschedulerStrategy, s conversion.Scope) error {
return autoConvert_api_DeschedulerStrategy_To_v1alpha1_DeschedulerStrategy(in, out, s)
}
func autoConvert_v1alpha1_NodeResourceUtilizationThresholds_To_api_NodeResourceUtilizationThresholds(in *NodeResourceUtilizationThresholds, out *api.NodeResourceUtilizationThresholds, s conversion.Scope) error {
out.Thresholds = *(*api.ResourceThresholds)(unsafe.Pointer(&in.Thresholds))
out.TargetThresholds = *(*api.ResourceThresholds)(unsafe.Pointer(&in.TargetThresholds))
out.NumberOfNodes = in.NumberOfNodes
return nil
}
// Convert_v1alpha1_NodeResourceUtilizationThresholds_To_api_NodeResourceUtilizationThresholds is an autogenerated conversion function.
func Convert_v1alpha1_NodeResourceUtilizationThresholds_To_api_NodeResourceUtilizationThresholds(in *NodeResourceUtilizationThresholds, out *api.NodeResourceUtilizationThresholds, s conversion.Scope) error {
return autoConvert_v1alpha1_NodeResourceUtilizationThresholds_To_api_NodeResourceUtilizationThresholds(in, out, s)
}
func autoConvert_api_NodeResourceUtilizationThresholds_To_v1alpha1_NodeResourceUtilizationThresholds(in *api.NodeResourceUtilizationThresholds, out *NodeResourceUtilizationThresholds, s conversion.Scope) error {
out.Thresholds = *(*ResourceThresholds)(unsafe.Pointer(&in.Thresholds))
out.TargetThresholds = *(*ResourceThresholds)(unsafe.Pointer(&in.TargetThresholds))
out.NumberOfNodes = in.NumberOfNodes
return nil
}
// Convert_api_NodeResourceUtilizationThresholds_To_v1alpha1_NodeResourceUtilizationThresholds is an autogenerated conversion function.
func Convert_api_NodeResourceUtilizationThresholds_To_v1alpha1_NodeResourceUtilizationThresholds(in *api.NodeResourceUtilizationThresholds, out *NodeResourceUtilizationThresholds, s conversion.Scope) error {
return autoConvert_api_NodeResourceUtilizationThresholds_To_v1alpha1_NodeResourceUtilizationThresholds(in, out, s)
}
func autoConvert_v1alpha1_StrategyParameters_To_api_StrategyParameters(in *StrategyParameters, out *api.StrategyParameters, s conversion.Scope) error {
if err := Convert_v1alpha1_NodeResourceUtilizationThresholds_To_api_NodeResourceUtilizationThresholds(&in.NodeResourceUtilizationThresholds, &out.NodeResourceUtilizationThresholds, s); err != nil {
return err
}
out.NodeAffinityType = *(*[]string)(unsafe.Pointer(&in.NodeAffinityType))
return nil
}
// Convert_v1alpha1_StrategyParameters_To_api_StrategyParameters is an autogenerated conversion function.
func Convert_v1alpha1_StrategyParameters_To_api_StrategyParameters(in *StrategyParameters, out *api.StrategyParameters, s conversion.Scope) error {
return autoConvert_v1alpha1_StrategyParameters_To_api_StrategyParameters(in, out, s)
}
func autoConvert_api_StrategyParameters_To_v1alpha1_StrategyParameters(in *api.StrategyParameters, out *StrategyParameters, s conversion.Scope) error {
if err := Convert_api_NodeResourceUtilizationThresholds_To_v1alpha1_NodeResourceUtilizationThresholds(&in.NodeResourceUtilizationThresholds, &out.NodeResourceUtilizationThresholds, s); err != nil {
return err
}
out.NodeAffinityType = *(*[]string)(unsafe.Pointer(&in.NodeAffinityType))
return nil
}
// Convert_api_StrategyParameters_To_v1alpha1_StrategyParameters is an autogenerated conversion function.
func Convert_api_StrategyParameters_To_v1alpha1_StrategyParameters(in *api.StrategyParameters, out *StrategyParameters, s conversion.Scope) error {
return autoConvert_api_StrategyParameters_To_v1alpha1_StrategyParameters(in, out, s)
}

View File

@@ -1,129 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeschedulerPolicy) DeepCopyInto(out *DeschedulerPolicy) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Strategies != nil {
in, out := &in.Strategies, &out.Strategies
*out = make(StrategyList, len(*in))
for key, val := range *in {
newVal := new(DeschedulerStrategy)
val.DeepCopyInto(newVal)
(*out)[key] = *newVal
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerPolicy.
func (in *DeschedulerPolicy) DeepCopy() *DeschedulerPolicy {
if in == nil {
return nil
}
out := new(DeschedulerPolicy)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DeschedulerPolicy) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeschedulerStrategy) DeepCopyInto(out *DeschedulerStrategy) {
*out = *in
in.Params.DeepCopyInto(&out.Params)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerStrategy.
func (in *DeschedulerStrategy) DeepCopy() *DeschedulerStrategy {
if in == nil {
return nil
}
out := new(DeschedulerStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeResourceUtilizationThresholds) DeepCopyInto(out *NodeResourceUtilizationThresholds) {
*out = *in
if in.Thresholds != nil {
in, out := &in.Thresholds, &out.Thresholds
*out = make(ResourceThresholds, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.TargetThresholds != nil {
in, out := &in.TargetThresholds, &out.TargetThresholds
*out = make(ResourceThresholds, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourceUtilizationThresholds.
func (in *NodeResourceUtilizationThresholds) DeepCopy() *NodeResourceUtilizationThresholds {
if in == nil {
return nil
}
out := new(NodeResourceUtilizationThresholds)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StrategyParameters) DeepCopyInto(out *StrategyParameters) {
*out = *in
in.NodeResourceUtilizationThresholds.DeepCopyInto(&out.NodeResourceUtilizationThresholds)
if in.NodeAffinityType != nil {
in, out := &in.NodeAffinityType, &out.NodeAffinityType
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyParameters.
func (in *StrategyParameters) DeepCopy() *StrategyParameters {
if in == nil {
return nil
}
out := new(StrategyParameters)
in.DeepCopyInto(out)
return out
}

View File

@@ -1,32 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by defaulter-gen. Do not edit it manually!
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@@ -1,129 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package api
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeschedulerPolicy) DeepCopyInto(out *DeschedulerPolicy) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Strategies != nil {
in, out := &in.Strategies, &out.Strategies
*out = make(StrategyList, len(*in))
for key, val := range *in {
newVal := new(DeschedulerStrategy)
val.DeepCopyInto(newVal)
(*out)[key] = *newVal
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerPolicy.
func (in *DeschedulerPolicy) DeepCopy() *DeschedulerPolicy {
if in == nil {
return nil
}
out := new(DeschedulerPolicy)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DeschedulerPolicy) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeschedulerStrategy) DeepCopyInto(out *DeschedulerStrategy) {
*out = *in
in.Params.DeepCopyInto(&out.Params)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerStrategy.
func (in *DeschedulerStrategy) DeepCopy() *DeschedulerStrategy {
if in == nil {
return nil
}
out := new(DeschedulerStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeResourceUtilizationThresholds) DeepCopyInto(out *NodeResourceUtilizationThresholds) {
*out = *in
if in.Thresholds != nil {
in, out := &in.Thresholds, &out.Thresholds
*out = make(ResourceThresholds, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.TargetThresholds != nil {
in, out := &in.TargetThresholds, &out.TargetThresholds
*out = make(ResourceThresholds, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourceUtilizationThresholds.
func (in *NodeResourceUtilizationThresholds) DeepCopy() *NodeResourceUtilizationThresholds {
if in == nil {
return nil
}
out := new(NodeResourceUtilizationThresholds)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StrategyParameters) DeepCopyInto(out *StrategyParameters) {
*out = *in
in.NodeResourceUtilizationThresholds.DeepCopyInto(&out.NodeResourceUtilizationThresholds)
if in.NodeAffinityType != nil {
in, out := &in.NodeAffinityType, &out.NodeAffinityType
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyParameters.
func (in *StrategyParameters) DeepCopy() *StrategyParameters {
if in == nil {
return nil
}
out := new(StrategyParameters)
in.DeepCopyInto(out)
return out
}

View File

@@ -1,19 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package,register
package componentconfig // import "github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig"

View File

@@ -1,48 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package install installs the descheduler's componentconfig API group.
package install
import (
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig"
"github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig/v1alpha1"
deschedulerscheme "github.com/kubernetes-incubator/descheduler/pkg/descheduler/scheme"
)
func init() {
Install(deschedulerscheme.GroupFactoryRegistry, deschedulerscheme.Registry, deschedulerscheme.Scheme)
}
// Install registers the API group and adds types to a scheme
func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{
GroupName: componentconfig.GroupName,
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version},
AddInternalObjectsToScheme: componentconfig.AddToScheme,
},
announced.VersionToSchemeFunc{
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
},
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
panic(err)
}
}

View File

@@ -1,50 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package componentconfig
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// GroupName is the group name used in this package
const GroupName = "deschedulercomponentconfig"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&DeschedulerConfiguration{},
)
return nil
}

View File

@@ -1,629 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by codecgen - DO NOT EDIT.
package componentconfig
import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg1_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"reflect"
"runtime"
time "time"
)
const (
// ----- content types ----
codecSelferCcUTF81234 = 1
codecSelferCcRAW1234 = 0
// ----- value types used ----
codecSelferValueTypeArray1234 = 10
codecSelferValueTypeMap1234 = 9
codecSelferValueTypeString1234 = 6
codecSelferValueTypeInt1234 = 2
codecSelferValueTypeUint1234 = 3
codecSelferValueTypeFloat1234 = 4
)
var (
codecSelferBitsize1234 = uint8(reflect.TypeOf(uint(0)).Bits())
errCodecSelferOnlyMapOrArrayEncodeToStruct1234 = errors.New(`only encoded map or array can be decoded into a struct`)
)
type codecSelfer1234 struct{}
func init() {
if codec1978.GenVersion != 8 {
_, file, _, _ := runtime.Caller(0)
err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v",
8, codec1978.GenVersion, file)
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg1_v1.TypeMeta
var v1 time.Duration
_, _ = v0, v1
}
}
func (x *DeschedulerConfiguration) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if yyxt1 := z.Extension(z.I2Rtid(x)); yyxt1 != nil {
z.EncExtension(x, yyxt1)
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [8]bool
_ = yyq2
_, _ = yysep2, yy2arr2
const yyr2 bool = false
yyq2[0] = x.Kind != ""
yyq2[1] = x.APIVersion != ""
if yyr2 || yy2arr2 {
r.WriteArrayStart(8)
} else {
var yynn2 = 6
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.WriteMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[0] {
yym4 := z.EncBinary()
_ = yym4
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.Kind))
}
} else {
r.EncodeString(codecSelferCcUTF81234, "")
}
} else {
if yyq2[0] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `kind`)
r.WriteMapElemValue()
yym5 := z.EncBinary()
_ = yym5
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.Kind))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[1] {
yym7 := z.EncBinary()
_ = yym7
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.APIVersion))
}
} else {
r.EncodeString(codecSelferCcUTF81234, "")
}
} else {
if yyq2[1] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `apiVersion`)
r.WriteMapElemValue()
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.APIVersion))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
yym10 := z.EncBinary()
_ = yym10
if false {
} else if yyxt10 := z.Extension(z.I2Rtid(x.DeschedulingInterval)); yyxt10 != nil {
z.EncExtension(x.DeschedulingInterval, yyxt10)
} else {
r.EncodeInt(int64(x.DeschedulingInterval))
}
} else {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `DeschedulingInterval`)
r.WriteMapElemValue()
yym11 := z.EncBinary()
_ = yym11
if false {
} else if yyxt11 := z.Extension(z.I2Rtid(x.DeschedulingInterval)); yyxt11 != nil {
z.EncExtension(x.DeschedulingInterval, yyxt11)
} else {
r.EncodeInt(int64(x.DeschedulingInterval))
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
yym13 := z.EncBinary()
_ = yym13
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.KubeconfigFile))
}
} else {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `KubeconfigFile`)
r.WriteMapElemValue()
yym14 := z.EncBinary()
_ = yym14
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.KubeconfigFile))
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
yym16 := z.EncBinary()
_ = yym16
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.PolicyConfigFile))
}
} else {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `PolicyConfigFile`)
r.WriteMapElemValue()
yym17 := z.EncBinary()
_ = yym17
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.PolicyConfigFile))
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
yym19 := z.EncBinary()
_ = yym19
if false {
} else {
r.EncodeBool(bool(x.DryRun))
}
} else {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `DryRun`)
r.WriteMapElemValue()
yym20 := z.EncBinary()
_ = yym20
if false {
} else {
r.EncodeBool(bool(x.DryRun))
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
yym22 := z.EncBinary()
_ = yym22
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.NodeSelector))
}
} else {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `NodeSelector`)
r.WriteMapElemValue()
yym23 := z.EncBinary()
_ = yym23
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.NodeSelector))
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
yym25 := z.EncBinary()
_ = yym25
if false {
} else {
r.EncodeInt(int64(x.MaxNoOfPodsToEvictPerNode))
}
} else {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `MaxNoOfPodsToEvictPerNode`)
r.WriteMapElemValue()
yym26 := z.EncBinary()
_ = yym26
if false {
} else {
r.EncodeInt(int64(x.MaxNoOfPodsToEvictPerNode))
}
}
if yyr2 || yy2arr2 {
r.WriteArrayEnd()
} else {
r.WriteMapEnd()
}
}
}
}
func (x *DeschedulerConfiguration) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if yyxt1 := z.Extension(z.I2Rtid(x)); yyxt1 != nil {
z.DecExtension(x, yyxt1)
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
r.ReadMapEnd()
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
r.ReadArrayEnd()
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(errCodecSelferOnlyMapOrArrayEncodeToStruct1234)
}
}
}
func (x *DeschedulerConfiguration) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
r.ReadMapElemKey()
yys3 := z.StringView(r.DecStructFieldKey(codecSelferValueTypeString1234, z.DecScratchArrayBuffer()))
r.ReadMapElemValue()
switch yys3 {
case "kind":
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
yyv4 := &x.Kind
yym5 := z.DecBinary()
_ = yym5
if false {
} else {
*((*string)(yyv4)) = r.DecodeString()
}
}
case "apiVersion":
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv6 := &x.APIVersion
yym7 := z.DecBinary()
_ = yym7
if false {
} else {
*((*string)(yyv6)) = r.DecodeString()
}
}
case "DeschedulingInterval":
if r.TryDecodeAsNil() {
x.DeschedulingInterval = 0
} else {
yyv8 := &x.DeschedulingInterval
yym9 := z.DecBinary()
_ = yym9
if false {
} else if yyxt9 := z.Extension(z.I2Rtid(yyv8)); yyxt9 != nil {
z.DecExtension(yyv8, yyxt9)
} else {
*((*int64)(yyv8)) = int64(r.DecodeInt(64))
}
}
case "KubeconfigFile":
if r.TryDecodeAsNil() {
x.KubeconfigFile = ""
} else {
yyv10 := &x.KubeconfigFile
yym11 := z.DecBinary()
_ = yym11
if false {
} else {
*((*string)(yyv10)) = r.DecodeString()
}
}
case "PolicyConfigFile":
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv12 := &x.PolicyConfigFile
yym13 := z.DecBinary()
_ = yym13
if false {
} else {
*((*string)(yyv12)) = r.DecodeString()
}
}
case "DryRun":
if r.TryDecodeAsNil() {
x.DryRun = false
} else {
yyv14 := &x.DryRun
yym15 := z.DecBinary()
_ = yym15
if false {
} else {
*((*bool)(yyv14)) = r.DecodeBool()
}
}
case "NodeSelector":
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv16 := &x.NodeSelector
yym17 := z.DecBinary()
_ = yym17
if false {
} else {
*((*string)(yyv16)) = r.DecodeString()
}
}
case "MaxNoOfPodsToEvictPerNode":
if r.TryDecodeAsNil() {
x.MaxNoOfPodsToEvictPerNode = 0
} else {
yyv18 := &x.MaxNoOfPodsToEvictPerNode
yym19 := z.DecBinary()
_ = yym19
if false {
} else {
*((*int)(yyv18)) = int(r.DecodeInt(codecSelferBitsize1234))
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
r.ReadMapEnd()
}
func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj20 int
var yyb20 bool
var yyhl20 bool = l >= 0
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
yyv21 := &x.Kind
yym22 := z.DecBinary()
_ = yym22
if false {
} else {
*((*string)(yyv21)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv23 := &x.APIVersion
yym24 := z.DecBinary()
_ = yym24
if false {
} else {
*((*string)(yyv23)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.DeschedulingInterval = 0
} else {
yyv25 := &x.DeschedulingInterval
yym26 := z.DecBinary()
_ = yym26
if false {
} else if yyxt26 := z.Extension(z.I2Rtid(yyv25)); yyxt26 != nil {
z.DecExtension(yyv25, yyxt26)
} else {
*((*int64)(yyv25)) = int64(r.DecodeInt(64))
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.KubeconfigFile = ""
} else {
yyv27 := &x.KubeconfigFile
yym28 := z.DecBinary()
_ = yym28
if false {
} else {
*((*string)(yyv27)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv29 := &x.PolicyConfigFile
yym30 := z.DecBinary()
_ = yym30
if false {
} else {
*((*string)(yyv29)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.DryRun = false
} else {
yyv31 := &x.DryRun
yym32 := z.DecBinary()
_ = yym32
if false {
} else {
*((*bool)(yyv31)) = r.DecodeBool()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv33 := &x.NodeSelector
yym34 := z.DecBinary()
_ = yym34
if false {
} else {
*((*string)(yyv33)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.MaxNoOfPodsToEvictPerNode = 0
} else {
yyv35 := &x.MaxNoOfPodsToEvictPerNode
yym36 := z.DecBinary()
_ = yym36
if false {
} else {
*((*int)(yyv35)) = int(r.DecodeInt(codecSelferBitsize1234))
}
}
for {
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
break
}
r.ReadArrayElem()
z.DecStructFieldNotFound(yyj20-1, "")
}
r.ReadArrayEnd()
}

View File

@@ -1,48 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package componentconfig
import (
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DeschedulerConfiguration struct {
metav1.TypeMeta
// Time interval for descheduler to run
DeschedulingInterval time.Duration
// KubeconfigFile is path to kubeconfig file with authorization and master
// location information.
KubeconfigFile string
// PolicyConfigFile is the filepath to the descheduler policy configuration.
PolicyConfigFile string
// Dry run
DryRun bool
// Node selectors
NodeSelector string
// MaxNoOfPodsToEvictPerNode restricts maximum of pods to be evicted per node.
MaxNoOfPodsToEvictPerNode int
}

View File

@@ -1,23 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import "k8s.io/apimachinery/pkg/runtime"
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}

View File

@@ -1,24 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig
// +k8s:defaulter-gen=TypeMeta
// Package v1alpha1 is the v1alpha1 version of the descheduler's componentconfig API
// +groupName=deschedulercomponentconfig
package v1alpha1 // import "github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig/v1alpha1"

View File

@@ -1,60 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
localSchemeBuilder = &SchemeBuilder
AddToScheme = SchemeBuilder.AddToScheme
)
// GroupName is the group name use in this package
const GroupName = "deschedulercomponentconfig"
const GroupVersion = "v1alpha1"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
}
func addKnownTypes(scheme *runtime.Scheme) error {
// TODO this will get cleaned up with the scheme types are fixed
scheme.AddKnownTypes(SchemeGroupVersion,
&DeschedulerConfiguration{},
)
return nil
}

View File

@@ -1,664 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by codecgen - DO NOT EDIT.
package v1alpha1
import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg1_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"reflect"
"runtime"
time "time"
)
const (
// ----- content types ----
codecSelferCcUTF81234 = 1
codecSelferCcRAW1234 = 0
// ----- value types used ----
codecSelferValueTypeArray1234 = 10
codecSelferValueTypeMap1234 = 9
codecSelferValueTypeString1234 = 6
codecSelferValueTypeInt1234 = 2
codecSelferValueTypeUint1234 = 3
codecSelferValueTypeFloat1234 = 4
)
var (
codecSelferBitsize1234 = uint8(reflect.TypeOf(uint(0)).Bits())
errCodecSelferOnlyMapOrArrayEncodeToStruct1234 = errors.New(`only encoded map or array can be decoded into a struct`)
)
type codecSelfer1234 struct{}
func init() {
if codec1978.GenVersion != 8 {
_, file, _, _ := runtime.Caller(0)
err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v",
8, codec1978.GenVersion, file)
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg1_v1.TypeMeta
var v1 time.Duration
_, _ = v0, v1
}
}
func (x *DeschedulerConfiguration) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if yyxt1 := z.Extension(z.I2Rtid(x)); yyxt1 != nil {
z.EncExtension(x, yyxt1)
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [8]bool
_ = yyq2
_, _ = yysep2, yy2arr2
const yyr2 bool = false
yyq2[0] = x.Kind != ""
yyq2[1] = x.APIVersion != ""
yyq2[2] = x.DeschedulingInterval != 0
yyq2[4] = x.PolicyConfigFile != ""
yyq2[5] = x.DryRun != false
yyq2[6] = x.NodeSelector != ""
yyq2[7] = x.MaxNoOfPodsToEvictPerNode != 0
if yyr2 || yy2arr2 {
r.WriteArrayStart(8)
} else {
var yynn2 = 1
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.WriteMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[0] {
yym4 := z.EncBinary()
_ = yym4
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.Kind))
}
} else {
r.EncodeString(codecSelferCcUTF81234, "")
}
} else {
if yyq2[0] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `kind`)
r.WriteMapElemValue()
yym5 := z.EncBinary()
_ = yym5
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.Kind))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[1] {
yym7 := z.EncBinary()
_ = yym7
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.APIVersion))
}
} else {
r.EncodeString(codecSelferCcUTF81234, "")
}
} else {
if yyq2[1] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `apiVersion`)
r.WriteMapElemValue()
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.APIVersion))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[2] {
yym10 := z.EncBinary()
_ = yym10
if false {
} else if yyxt10 := z.Extension(z.I2Rtid(x.DeschedulingInterval)); yyxt10 != nil {
z.EncExtension(x.DeschedulingInterval, yyxt10)
} else {
r.EncodeInt(int64(x.DeschedulingInterval))
}
} else {
r.EncodeInt(0)
}
} else {
if yyq2[2] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `deschedulingInterval`)
r.WriteMapElemValue()
yym11 := z.EncBinary()
_ = yym11
if false {
} else if yyxt11 := z.Extension(z.I2Rtid(x.DeschedulingInterval)); yyxt11 != nil {
z.EncExtension(x.DeschedulingInterval, yyxt11)
} else {
r.EncodeInt(int64(x.DeschedulingInterval))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
yym13 := z.EncBinary()
_ = yym13
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.KubeconfigFile))
}
} else {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `kubeconfigFile`)
r.WriteMapElemValue()
yym14 := z.EncBinary()
_ = yym14
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.KubeconfigFile))
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[4] {
yym16 := z.EncBinary()
_ = yym16
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.PolicyConfigFile))
}
} else {
r.EncodeString(codecSelferCcUTF81234, "")
}
} else {
if yyq2[4] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `policyConfigFile`)
r.WriteMapElemValue()
yym17 := z.EncBinary()
_ = yym17
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.PolicyConfigFile))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[5] {
yym19 := z.EncBinary()
_ = yym19
if false {
} else {
r.EncodeBool(bool(x.DryRun))
}
} else {
r.EncodeBool(false)
}
} else {
if yyq2[5] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `dryRun`)
r.WriteMapElemValue()
yym20 := z.EncBinary()
_ = yym20
if false {
} else {
r.EncodeBool(bool(x.DryRun))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[6] {
yym22 := z.EncBinary()
_ = yym22
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.NodeSelector))
}
} else {
r.EncodeString(codecSelferCcUTF81234, "")
}
} else {
if yyq2[6] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `nodeSelector`)
r.WriteMapElemValue()
yym23 := z.EncBinary()
_ = yym23
if false {
} else {
r.EncodeString(codecSelferCcUTF81234, string(x.NodeSelector))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayElem()
if yyq2[7] {
yym25 := z.EncBinary()
_ = yym25
if false {
} else {
r.EncodeInt(int64(x.MaxNoOfPodsToEvictPerNode))
}
} else {
r.EncodeInt(0)
}
} else {
if yyq2[7] {
r.WriteMapElemKey()
r.EncStructFieldKey(codecSelferValueTypeString1234, `maxNoOfPodsToEvictPerNode`)
r.WriteMapElemValue()
yym26 := z.EncBinary()
_ = yym26
if false {
} else {
r.EncodeInt(int64(x.MaxNoOfPodsToEvictPerNode))
}
}
}
if yyr2 || yy2arr2 {
r.WriteArrayEnd()
} else {
r.WriteMapEnd()
}
}
}
}
func (x *DeschedulerConfiguration) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if yyxt1 := z.Extension(z.I2Rtid(x)); yyxt1 != nil {
z.DecExtension(x, yyxt1)
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
r.ReadMapEnd()
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
r.ReadArrayEnd()
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(errCodecSelferOnlyMapOrArrayEncodeToStruct1234)
}
}
}
func (x *DeschedulerConfiguration) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
r.ReadMapElemKey()
yys3 := z.StringView(r.DecStructFieldKey(codecSelferValueTypeString1234, z.DecScratchArrayBuffer()))
r.ReadMapElemValue()
switch yys3 {
case "kind":
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
yyv4 := &x.Kind
yym5 := z.DecBinary()
_ = yym5
if false {
} else {
*((*string)(yyv4)) = r.DecodeString()
}
}
case "apiVersion":
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv6 := &x.APIVersion
yym7 := z.DecBinary()
_ = yym7
if false {
} else {
*((*string)(yyv6)) = r.DecodeString()
}
}
case "deschedulingInterval":
if r.TryDecodeAsNil() {
x.DeschedulingInterval = 0
} else {
yyv8 := &x.DeschedulingInterval
yym9 := z.DecBinary()
_ = yym9
if false {
} else if yyxt9 := z.Extension(z.I2Rtid(yyv8)); yyxt9 != nil {
z.DecExtension(yyv8, yyxt9)
} else {
*((*int64)(yyv8)) = int64(r.DecodeInt(64))
}
}
case "kubeconfigFile":
if r.TryDecodeAsNil() {
x.KubeconfigFile = ""
} else {
yyv10 := &x.KubeconfigFile
yym11 := z.DecBinary()
_ = yym11
if false {
} else {
*((*string)(yyv10)) = r.DecodeString()
}
}
case "policyConfigFile":
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv12 := &x.PolicyConfigFile
yym13 := z.DecBinary()
_ = yym13
if false {
} else {
*((*string)(yyv12)) = r.DecodeString()
}
}
case "dryRun":
if r.TryDecodeAsNil() {
x.DryRun = false
} else {
yyv14 := &x.DryRun
yym15 := z.DecBinary()
_ = yym15
if false {
} else {
*((*bool)(yyv14)) = r.DecodeBool()
}
}
case "nodeSelector":
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv16 := &x.NodeSelector
yym17 := z.DecBinary()
_ = yym17
if false {
} else {
*((*string)(yyv16)) = r.DecodeString()
}
}
case "maxNoOfPodsToEvictPerNode":
if r.TryDecodeAsNil() {
x.MaxNoOfPodsToEvictPerNode = 0
} else {
yyv18 := &x.MaxNoOfPodsToEvictPerNode
yym19 := z.DecBinary()
_ = yym19
if false {
} else {
*((*int)(yyv18)) = int(r.DecodeInt(codecSelferBitsize1234))
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
r.ReadMapEnd()
}
func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj20 int
var yyb20 bool
var yyhl20 bool = l >= 0
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
yyv21 := &x.Kind
yym22 := z.DecBinary()
_ = yym22
if false {
} else {
*((*string)(yyv21)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv23 := &x.APIVersion
yym24 := z.DecBinary()
_ = yym24
if false {
} else {
*((*string)(yyv23)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.DeschedulingInterval = 0
} else {
yyv25 := &x.DeschedulingInterval
yym26 := z.DecBinary()
_ = yym26
if false {
} else if yyxt26 := z.Extension(z.I2Rtid(yyv25)); yyxt26 != nil {
z.DecExtension(yyv25, yyxt26)
} else {
*((*int64)(yyv25)) = int64(r.DecodeInt(64))
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.KubeconfigFile = ""
} else {
yyv27 := &x.KubeconfigFile
yym28 := z.DecBinary()
_ = yym28
if false {
} else {
*((*string)(yyv27)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv29 := &x.PolicyConfigFile
yym30 := z.DecBinary()
_ = yym30
if false {
} else {
*((*string)(yyv29)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.DryRun = false
} else {
yyv31 := &x.DryRun
yym32 := z.DecBinary()
_ = yym32
if false {
} else {
*((*bool)(yyv31)) = r.DecodeBool()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv33 := &x.NodeSelector
yym34 := z.DecBinary()
_ = yym34
if false {
} else {
*((*string)(yyv33)) = r.DecodeString()
}
}
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
r.ReadArrayEnd()
return
}
r.ReadArrayElem()
if r.TryDecodeAsNil() {
x.MaxNoOfPodsToEvictPerNode = 0
} else {
yyv35 := &x.MaxNoOfPodsToEvictPerNode
yym36 := z.DecBinary()
_ = yym36
if false {
} else {
*((*int)(yyv35)) = int(r.DecodeInt(codecSelferBitsize1234))
}
}
for {
yyj20++
if yyhl20 {
yyb20 = yyj20 > l
} else {
yyb20 = r.CheckBreak()
}
if yyb20 {
break
}
r.ReadArrayElem()
z.DecStructFieldNotFound(yyj20-1, "")
}
r.ReadArrayEnd()
}

View File

@@ -1,48 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DeschedulerConfiguration struct {
metav1.TypeMeta `json:",inline"`
// Time interval for descheduler to run
DeschedulingInterval time.Duration `json:"deschedulingInterval,omitempty"`
// KubeconfigFile is path to kubeconfig file with authorization and master
// location information.
KubeconfigFile string `json:"kubeconfigFile"`
// PolicyConfigFile is the filepath to the descheduler policy configuration.
PolicyConfigFile string `json:"policyConfigFile,omitempty"`
// Dry run
DryRun bool `json:"dryRun,omitempty"`
// Node selectors
NodeSelector string `json:"nodeSelector,omitempty"`
// MaxNoOfPodsToEvictPerNode restricts maximum of pods to be evicted per node.
MaxNoOfPodsToEvictPerNode int `json:"maxNoOfPodsToEvictPerNode,omitempty"`
}

View File

@@ -1,72 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
package v1alpha1
import (
time "time"
componentconfig "github.com/kubernetes-incubator/descheduler/pkg/apis/componentconfig"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_DeschedulerConfiguration_To_componentconfig_DeschedulerConfiguration,
Convert_componentconfig_DeschedulerConfiguration_To_v1alpha1_DeschedulerConfiguration,
)
}
func autoConvert_v1alpha1_DeschedulerConfiguration_To_componentconfig_DeschedulerConfiguration(in *DeschedulerConfiguration, out *componentconfig.DeschedulerConfiguration, s conversion.Scope) error {
out.DeschedulingInterval = time.Duration(in.DeschedulingInterval)
out.KubeconfigFile = in.KubeconfigFile
out.PolicyConfigFile = in.PolicyConfigFile
out.DryRun = in.DryRun
out.NodeSelector = in.NodeSelector
out.MaxNoOfPodsToEvictPerNode = in.MaxNoOfPodsToEvictPerNode
return nil
}
// Convert_v1alpha1_DeschedulerConfiguration_To_componentconfig_DeschedulerConfiguration is an autogenerated conversion function.
func Convert_v1alpha1_DeschedulerConfiguration_To_componentconfig_DeschedulerConfiguration(in *DeschedulerConfiguration, out *componentconfig.DeschedulerConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha1_DeschedulerConfiguration_To_componentconfig_DeschedulerConfiguration(in, out, s)
}
func autoConvert_componentconfig_DeschedulerConfiguration_To_v1alpha1_DeschedulerConfiguration(in *componentconfig.DeschedulerConfiguration, out *DeschedulerConfiguration, s conversion.Scope) error {
out.DeschedulingInterval = time.Duration(in.DeschedulingInterval)
out.KubeconfigFile = in.KubeconfigFile
out.PolicyConfigFile = in.PolicyConfigFile
out.DryRun = in.DryRun
out.NodeSelector = in.NodeSelector
out.MaxNoOfPodsToEvictPerNode = in.MaxNoOfPodsToEvictPerNode
return nil
}
// Convert_componentconfig_DeschedulerConfiguration_To_v1alpha1_DeschedulerConfiguration is an autogenerated conversion function.
func Convert_componentconfig_DeschedulerConfiguration_To_v1alpha1_DeschedulerConfiguration(in *componentconfig.DeschedulerConfiguration, out *DeschedulerConfiguration, s conversion.Scope) error {
return autoConvert_componentconfig_DeschedulerConfiguration_To_v1alpha1_DeschedulerConfiguration(in, out, s)
}

View File

@@ -1,51 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeschedulerConfiguration) DeepCopyInto(out *DeschedulerConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerConfiguration.
func (in *DeschedulerConfiguration) DeepCopy() *DeschedulerConfiguration {
if in == nil {
return nil
}
out := new(DeschedulerConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DeschedulerConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}

View File

@@ -1,32 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by defaulter-gen. Do not edit it manually!
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@@ -1,51 +0,0 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package componentconfig
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeschedulerConfiguration) DeepCopyInto(out *DeschedulerConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerConfiguration.
func (in *DeschedulerConfiguration) DeepCopy() *DeschedulerConfiguration {
if in == nil {
return nil
}
out := new(DeschedulerConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DeschedulerConfiguration) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
} else {
return nil
}
}

View File

@@ -1,66 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"fmt"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
func CreateClient(kubeconfig string) (clientset.Interface, error) {
var cfg *rest.Config
if len(kubeconfig) != 0 {
master, err := GetMasterFromKubeconfig(kubeconfig)
if err != nil {
return nil, fmt.Errorf("Failed to parse kubeconfig file: %v ", err)
}
cfg, err = clientcmd.BuildConfigFromFlags(master, kubeconfig)
if err != nil {
return nil, fmt.Errorf("Unable to build config: %v", err)
}
} else {
var err error
cfg, err = rest.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("Unable to build in cluster config: %v", err)
}
}
return clientset.NewForConfig(cfg)
}
func GetMasterFromKubeconfig(filename string) (string, error) {
config, err := clientcmd.LoadFromFile(filename)
if err != nil {
return "", err
}
context, ok := config.Contexts[config.CurrentContext]
if !ok {
return "", fmt.Errorf("Failed to get master address from kubeconfig")
}
if val, ok := config.Clusters[context.Cluster]; ok {
return val.Server, nil
}
return "", fmt.Errorf("Failed to get master address from kubeconfig")
}

View File

@@ -1,70 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package descheduler
import (
"fmt"
"github.com/golang/glog"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/client"
eutils "github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions/utils"
nodeutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/node"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/strategies"
)
func Run(rs *options.DeschedulerServer) error {
rsclient, err := client.CreateClient(rs.KubeconfigFile)
if err != nil {
return err
}
rs.Client = rsclient
deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile)
if err != nil {
return err
}
if deschedulerPolicy == nil {
return fmt.Errorf("deschedulerPolicy is nil")
}
evictionPolicyGroupVersion, err := eutils.SupportEviction(rs.Client)
if err != nil || len(evictionPolicyGroupVersion) == 0 {
return err
}
stopChannel := make(chan struct{})
nodes, err := nodeutil.ReadyNodes(rs.Client, rs.NodeSelector, stopChannel)
if err != nil {
return err
}
if len(nodes) <= 1 {
glog.V(1).Infof("The cluster size is 0 or 1 meaning eviction causes service disruption or degradation. So aborting..")
return nil
}
nodePodCount := strategies.InitializeNodePodCount(nodes)
strategies.RemoveDuplicatePods(rs, deschedulerPolicy.Strategies["RemoveDuplicates"], evictionPolicyGroupVersion, nodes, nodePodCount)
strategies.LowNodeUtilization(rs, deschedulerPolicy.Strategies["LowNodeUtilization"], evictionPolicyGroupVersion, nodes, nodePodCount)
strategies.RemovePodsViolatingInterPodAntiAffinity(rs, deschedulerPolicy.Strategies["RemovePodsViolatingInterPodAntiAffinity"], evictionPolicyGroupVersion, nodes, nodePodCount)
strategies.RemovePodsViolatingNodeAffinity(rs, deschedulerPolicy.Strategies["RemovePodsViolatingNodeAffinity"], evictionPolicyGroupVersion, nodes, nodePodCount)
return nil
}

View File

@@ -1,59 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package evictions
import (
"fmt"
"k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
eutils "github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions/utils"
)
func EvictPod(client clientset.Interface, pod *v1.Pod, policyGroupVersion string, dryRun bool) (bool, error) {
if dryRun {
return true, nil
}
deleteOptions := &metav1.DeleteOptions{}
// GracePeriodSeconds ?
eviction := &policy.Eviction{
TypeMeta: metav1.TypeMeta{
APIVersion: policyGroupVersion,
Kind: eutils.EvictionKind,
},
ObjectMeta: metav1.ObjectMeta{
Name: pod.Name,
Namespace: pod.Namespace,
},
DeleteOptions: deleteOptions,
}
err := client.Policy().Evictions(eviction.Namespace).Evict(eviction)
if err == nil {
return true, nil
} else if apierrors.IsTooManyRequests(err) {
return false, fmt.Errorf("error when evicting pod (ignoring) %q: %v", pod.Name, err)
} else if apierrors.IsNotFound(err) {
return true, fmt.Errorf("pod not found when evicting %q: %v", pod.Name, err)
} else {
return false, err
}
}

View File

@@ -1,40 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package evictions
import (
"github.com/kubernetes-incubator/descheduler/test"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
"testing"
)
func TestEvictPod(t *testing.T) {
n1 := test.BuildTestNode("node1", 1000, 2000, 9)
p1 := test.BuildTestPod("p1", 400, 0, n1.Name)
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.PodList{Items: []v1.Pod{*p1}}, nil
})
evicted, _ := EvictPod(fakeClient, p1, "v1", false)
if !evicted {
t.Errorf("Expected %v pod to be evicted", p1.Name)
}
}

View File

@@ -1,58 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
clientset "k8s.io/client-go/kubernetes"
)
const (
EvictionKind = "Eviction"
EvictionSubresource = "pods/eviction"
)
// SupportEviction uses Discovery API to find out if the server support eviction subresource
// If support, it will return its groupVersion; Otherwise, it will return ""
func SupportEviction(client clientset.Interface) (string, error) {
discoveryClient := client.Discovery()
groupList, err := discoveryClient.ServerGroups()
if err != nil {
return "", err
}
foundPolicyGroup := false
var policyGroupVersion string
for _, group := range groupList.Groups {
if group.Name == "policy" {
foundPolicyGroup = true
policyGroupVersion = group.PreferredVersion.GroupVersion
break
}
}
if !foundPolicyGroup {
return "", nil
}
resourceList, err := discoveryClient.ServerResourcesForGroupVersion("v1")
if err != nil {
return "", err
}
for _, resource := range resourceList.APIResources {
if resource.Name == EvictionSubresource && resource.Kind == EvictionKind {
return policyGroupVersion, nil
}
}
return "", nil
}

View File

@@ -1,167 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package node
import (
"time"
"github.com/golang/glog"
"github.com/kubernetes-incubator/descheduler/pkg/utils"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
clientset "k8s.io/client-go/kubernetes"
corelisters "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
)
// ReadyNodes returns ready nodes irrespective of whether they are
// schedulable or not.
func ReadyNodes(client clientset.Interface, nodeSelector string, stopChannel <-chan struct{}) ([]*v1.Node, error) {
ns, err := labels.Parse(nodeSelector)
if err != nil {
return []*v1.Node{}, err
}
var nodes []*v1.Node
nl := GetNodeLister(client, stopChannel)
if nl != nil {
// err is defined above
if nodes, err = nl.List(ns); err != nil {
return []*v1.Node{}, err
}
}
if len(nodes) == 0 {
glog.V(2).Infof("node lister returned empty list, now fetch directly")
nItems, err := client.Core().Nodes().List(metav1.ListOptions{LabelSelector: nodeSelector})
if err != nil {
return []*v1.Node{}, err
}
if nItems == nil || len(nItems.Items) == 0 {
return []*v1.Node{}, nil
}
for i := range nItems.Items {
node := nItems.Items[i]
nodes = append(nodes, &node)
}
}
readyNodes := make([]*v1.Node, 0, len(nodes))
for _, node := range nodes {
if IsReady(node) {
readyNodes = append(readyNodes, node)
}
}
return readyNodes, nil
}
func GetNodeLister(client clientset.Interface, stopChannel <-chan struct{}) corelisters.NodeLister {
if stopChannel == nil {
return nil
}
listWatcher := cache.NewListWatchFromClient(client.Core().RESTClient(), "nodes", v1.NamespaceAll, fields.Everything())
store := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
nodeLister := corelisters.NewNodeLister(store)
reflector := cache.NewReflector(listWatcher, &v1.Node{}, store, time.Hour)
go reflector.Run(stopChannel)
// To give some time so that listing works, chosen randomly
time.Sleep(100 * time.Millisecond)
return nodeLister
}
// IsReady checks if the descheduler could run against given node.
func IsReady(node *v1.Node) bool {
for i := range node.Status.Conditions {
cond := &node.Status.Conditions[i]
// We consider the node for scheduling only when its:
// - NodeReady condition status is ConditionTrue,
// - NodeOutOfDisk condition status is ConditionFalse,
// - NodeNetworkUnavailable condition status is ConditionFalse.
if cond.Type == v1.NodeReady && cond.Status != v1.ConditionTrue {
glog.V(1).Infof("Ignoring node %v with %v condition status %v", node.Name, cond.Type, cond.Status)
return false
} /*else if cond.Type == v1.NodeOutOfDisk && cond.Status != v1.ConditionFalse {
glog.V(4).Infof("Ignoring node %v with %v condition status %v", node.Name, cond.Type, cond.Status)
return false
} else if cond.Type == v1.NodeNetworkUnavailable && cond.Status != v1.ConditionFalse {
glog.V(4).Infof("Ignoring node %v with %v condition status %v", node.Name, cond.Type, cond.Status)
return false
}*/
}
// Ignore nodes that are marked unschedulable
/*if node.Spec.Unschedulable {
glog.V(4).Infof("Ignoring node %v since it is unschedulable", node.Name)
return false
}*/
return true
}
// IsNodeUschedulable checks if the node is unschedulable. This is helper function to check only in case of
// underutilized node so that they won't be accounted for.
func IsNodeUschedulable(node *v1.Node) bool {
if node.Spec.Unschedulable {
return true
}
return false
}
// PodFitsAnyNode checks if the given pod fits any of the given nodes, based on
// multiple criteria, like, pod node selector matching the node label, node
// being schedulable or not.
func PodFitsAnyNode(pod *v1.Pod, nodes []*v1.Node) bool {
for _, node := range nodes {
ok, err := utils.PodMatchNodeSelector(pod, node)
if err != nil || !ok {
continue
}
if ok {
if !IsNodeUschedulable(node) {
glog.V(2).Infof("Pod %v can possibly be scheduled on %v", pod.Name, node.Name)
return true
}
return false
}
}
return false
}
// PodFitsCurrentNode checks if the given pod fits on the given node if the pod
// node selector matches the node label.
func PodFitsCurrentNode(pod *v1.Pod, node *v1.Node) bool {
ok, err := utils.PodMatchNodeSelector(pod, node)
if err != nil {
glog.Error(err)
return false
}
if !ok {
glog.V(1).Infof("Pod %v does not fit on node %v", pod.Name, node.Name)
return false
}
glog.V(3).Infof("Pod %v fits on node %v", pod.Name, node.Name)
return true
}

View File

@@ -1,347 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package node
import (
"testing"
"github.com/kubernetes-incubator/descheduler/test"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func TestReadyNodes(t *testing.T) {
node1 := test.BuildTestNode("node1", 1000, 2000, 9)
node1.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue}}
node2 := test.BuildTestNode("node2", 1000, 2000, 9)
node3 := test.BuildTestNode("node3", 1000, 2000, 9)
node3.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeMemoryPressure, Status: v1.ConditionTrue}}
node4 := test.BuildTestNode("node4", 1000, 2000, 9)
node4.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeNetworkUnavailable, Status: v1.ConditionTrue}}
node5 := test.BuildTestNode("node5", 1000, 2000, 9)
node5.Spec.Unschedulable = true
node6 := test.BuildTestNode("node6", 1000, 2000, 9)
node6.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionFalse}}
if !IsReady(node1) {
t.Errorf("Expected %v to be ready", node1.Name)
}
if !IsReady(node2) {
t.Errorf("Expected %v to be ready", node2.Name)
}
if !IsReady(node3) {
t.Errorf("Expected %v to be ready", node3.Name)
}
if !IsReady(node4) {
t.Errorf("Expected %v to be ready", node4.Name)
}
if !IsReady(node5) {
t.Errorf("Expected %v to be ready", node5.Name)
}
if IsReady(node6) {
t.Errorf("Expected %v to be not ready", node6.Name)
}
}
func TestReadyNodesWithNodeSelector(t *testing.T) {
node1 := test.BuildTestNode("node1", 1000, 2000, 9)
node1.Labels = map[string]string{"type": "compute"}
node2 := test.BuildTestNode("node2", 1000, 2000, 9)
node2.Labels = map[string]string{"type": "infra"}
fakeClient := fake.NewSimpleClientset(node1, node2)
nodeSelector := "type=compute"
nodes, _ := ReadyNodes(fakeClient, nodeSelector, nil)
if nodes[0].Name != "node1" {
t.Errorf("Expected node1, got %s", nodes[0].Name)
}
}
func TestIsNodeUschedulable(t *testing.T) {
tests := []struct {
description string
node *v1.Node
IsUnSchedulable bool
}{
{
description: "Node is expected to be schedulable",
node: &v1.Node{
Spec: v1.NodeSpec{Unschedulable: false},
},
IsUnSchedulable: false,
},
{
description: "Node is not expected to be schedulable because of unschedulable field",
node: &v1.Node{
Spec: v1.NodeSpec{Unschedulable: true},
},
IsUnSchedulable: true,
},
}
for _, test := range tests {
actualUnSchedulable := IsNodeUschedulable(test.node)
if actualUnSchedulable != test.IsUnSchedulable {
t.Errorf("Test %#v failed", test.description)
}
}
}
func TestPodFitsCurrentNode(t *testing.T) {
nodeLabelKey := "kubernetes.io/desiredNode"
nodeLabelValue := "yes"
tests := []struct {
description string
pod *v1.Pod
node *v1.Node
success bool
}{
{
description: "Pod with nodeAffinity set, expected to fit the node",
pod: &v1.Pod{
Spec: v1.PodSpec{
Affinity: &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: nodeLabelKey,
Operator: "In",
Values: []string{
nodeLabelValue,
},
},
},
},
},
},
},
},
},
},
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: nodeLabelValue,
},
},
},
success: true,
},
{
description: "Pod with nodeAffinity set, not expected to fit the node",
pod: &v1.Pod{
Spec: v1.PodSpec{
Affinity: &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: nodeLabelKey,
Operator: "In",
Values: []string{
nodeLabelValue,
},
},
},
},
},
},
},
},
},
},
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: "no",
},
},
},
success: false,
},
}
for _, tc := range tests {
actual := PodFitsCurrentNode(tc.pod, tc.node)
if actual != tc.success {
t.Errorf("Test %#v failed", tc.description)
}
}
}
func TestPodFitsAnyNode(t *testing.T) {
nodeLabelKey := "kubernetes.io/desiredNode"
nodeLabelValue := "yes"
tests := []struct {
description string
pod *v1.Pod
nodes []*v1.Node
success bool
}{
{
description: "Pod expected to fit one of the nodes",
pod: &v1.Pod{
Spec: v1.PodSpec{
Affinity: &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: nodeLabelKey,
Operator: "In",
Values: []string{
nodeLabelValue,
},
},
},
},
},
},
},
},
},
},
nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: nodeLabelValue,
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: "no",
},
},
},
},
success: true,
},
{
description: "Pod expected to fit none of the nodes",
pod: &v1.Pod{
Spec: v1.PodSpec{
Affinity: &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: nodeLabelKey,
Operator: "In",
Values: []string{
nodeLabelValue,
},
},
},
},
},
},
},
},
},
},
nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: "unfit1",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: "unfit2",
},
},
},
},
success: false,
},
{
description: "Nodes are unschedulable but labels match, should fail",
pod: &v1.Pod{
Spec: v1.PodSpec{
Affinity: &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: nodeLabelKey,
Operator: "In",
Values: []string{
nodeLabelValue,
},
},
},
},
},
},
},
},
},
},
nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: nodeLabelValue,
},
},
Spec: v1.NodeSpec{
Unschedulable: true,
},
},
{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
nodeLabelKey: "no",
},
},
},
},
success: false,
},
}
for _, tc := range tests {
actual := PodFitsAnyNode(tc.pod, tc.nodes)
if actual != tc.success {
t.Errorf("Test %#v failed", tc.description)
}
}
}

View File

@@ -1,143 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pod
import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
clientset "k8s.io/client-go/kubernetes"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/v1/helper/qos"
"k8s.io/kubernetes/pkg/kubelet/types"
)
// checkLatencySensitiveResourcesForAContainer checks if there are any latency sensitive resources like GPUs.
func checkLatencySensitiveResourcesForAContainer(rl v1.ResourceList) bool {
if rl == nil {
return false
}
for rName := range rl {
if rName == v1.ResourceNvidiaGPU {
return true
}
// TODO: Add support for other high value resources like hugepages etc. once kube is rebased to 1.8.
}
return false
}
// IsLatencySensitivePod checks if a pod consumes high value devices like GPUs, hugepages or when cpu pinning enabled.
func IsLatencySensitivePod(pod *v1.Pod) bool {
for _, container := range pod.Spec.Containers {
resourceList := container.Resources.Requests
if checkLatencySensitiveResourcesForAContainer(resourceList) {
return true
}
}
return false
}
// IsEvictable checks if a pod is evictable or not.
func IsEvictable(pod *v1.Pod) bool {
ownerRefList := OwnerRef(pod)
if IsMirrorPod(pod) || IsPodWithLocalStorage(pod) || len(ownerRefList) == 0 || IsDaemonsetPod(ownerRefList) || IsCriticalPod(pod) {
return false
}
return true
}
// ListEvictablePodsOnNode returns the list of evictable pods on node.
func ListEvictablePodsOnNode(client clientset.Interface, node *v1.Node) ([]*v1.Pod, error) {
pods, err := ListPodsOnANode(client, node)
if err != nil {
return []*v1.Pod{}, err
}
evictablePods := make([]*v1.Pod, 0)
for _, pod := range pods {
if !IsEvictable(pod) {
continue
} else {
evictablePods = append(evictablePods, pod)
}
}
return evictablePods, nil
}
func ListPodsOnANode(client clientset.Interface, node *v1.Node) ([]*v1.Pod, error) {
fieldSelector, err := fields.ParseSelector("spec.nodeName=" + node.Name + ",status.phase!=" + string(api.PodSucceeded) + ",status.phase!=" + string(api.PodFailed))
if err != nil {
return []*v1.Pod{}, err
}
podList, err := client.CoreV1().Pods(v1.NamespaceAll).List(
metav1.ListOptions{FieldSelector: fieldSelector.String()})
if err != nil {
return []*v1.Pod{}, err
}
pods := make([]*v1.Pod, 0)
for i := range podList.Items {
pods = append(pods, &podList.Items[i])
}
return pods, nil
}
func IsCriticalPod(pod *v1.Pod) bool {
return types.IsCriticalPod(pod)
}
func IsBestEffortPod(pod *v1.Pod) bool {
return qos.GetPodQOS(pod) == v1.PodQOSBestEffort
}
func IsBurstablePod(pod *v1.Pod) bool {
return qos.GetPodQOS(pod) == v1.PodQOSBurstable
}
func IsGuaranteedPod(pod *v1.Pod) bool {
return qos.GetPodQOS(pod) == v1.PodQOSGuaranteed
}
func IsDaemonsetPod(ownerRefList []metav1.OwnerReference) bool {
for _, ownerRef := range ownerRefList {
if ownerRef.Kind == "DaemonSet" {
return true
}
}
return false
}
// IsMirrorPod checks whether the pod is a mirror pod.
func IsMirrorPod(pod *v1.Pod) bool {
_, found := pod.ObjectMeta.Annotations[types.ConfigMirrorAnnotationKey]
return found
}
func IsPodWithLocalStorage(pod *v1.Pod) bool {
for _, volume := range pod.Spec.Volumes {
if volume.HostPath != nil || volume.EmptyDir != nil {
return true
}
}
return false
}
// OwnerRef returns the ownerRefList for the pod.
func OwnerRef(pod *v1.Pod) []metav1.OwnerReference {
return pod.ObjectMeta.GetOwnerReferences()
}

View File

@@ -1,84 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pod
import (
"testing"
"github.com/kubernetes-incubator/descheduler/test"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
func TestPodTypes(t *testing.T) {
n1 := test.BuildTestNode("node1", 1000, 2000, 9)
p1 := test.BuildTestPod("p1", 400, 0, n1.Name)
// These won't be evicted.
p2 := test.BuildTestPod("p2", 400, 0, n1.Name)
p3 := test.BuildTestPod("p3", 400, 0, n1.Name)
p4 := test.BuildTestPod("p4", 400, 0, n1.Name)
p5 := test.BuildTestPod("p5", 400, 0, n1.Name)
p6 := test.BuildTestPod("p6", 400, 0, n1.Name)
p6.Spec.Containers[0].Resources.Requests[v1.ResourceNvidiaGPU] = *resource.NewMilliQuantity(3, resource.DecimalSI)
p6.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
p1.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
// The following 4 pods won't get evicted.
// A daemonset.
//p2.Annotations = test.GetDaemonSetAnnotation()
p2.ObjectMeta.OwnerReferences = test.GetDaemonSetOwnerRefList()
// A pod with local storage.
p3.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
p3.Spec.Volumes = []v1.Volume{
{
Name: "sample",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{Path: "somePath"},
EmptyDir: &v1.EmptyDirVolumeSource{
SizeLimit: resource.NewQuantity(int64(10), resource.BinarySI)},
},
},
}
// A Mirror Pod.
p4.Annotations = test.GetMirrorPodAnnotation()
// A Critical Pod.
p5.Namespace = "kube-system"
p5.Annotations = test.GetCriticalPodAnnotation()
if !IsMirrorPod(p4) {
t.Errorf("Expected p4 to be a mirror pod.")
}
if !IsCriticalPod(p5) {
t.Errorf("Expected p5 to be a critical pod.")
}
if !IsPodWithLocalStorage(p3) {
t.Errorf("Expected p3 to be a pod with local storage.")
}
ownerRefList := OwnerRef(p2)
if !IsDaemonsetPod(ownerRefList) {
t.Errorf("Expected p2 to be a daemonset pod.")
}
ownerRefList = OwnerRef(p1)
if IsDaemonsetPod(ownerRefList) || IsPodWithLocalStorage(p1) || IsCriticalPod(p1) || IsMirrorPod(p1) {
t.Errorf("Expected p1 to be a normal pod.")
}
if !IsLatencySensitivePod(p6) {
t.Errorf("Expected p6 to be latency sensitive pod")
}
}

View File

@@ -1,56 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package descheduler
import (
"fmt"
"io/ioutil"
"k8s.io/apimachinery/pkg/runtime"
"github.com/golang/glog"
"github.com/kubernetes-incubator/descheduler/pkg/api"
_ "github.com/kubernetes-incubator/descheduler/pkg/api/install"
"github.com/kubernetes-incubator/descheduler/pkg/api/v1alpha1"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/scheme"
)
func LoadPolicyConfig(policyConfigFile string) (*api.DeschedulerPolicy, error) {
if policyConfigFile == "" {
glog.V(1).Infof("policy config file not specified")
return nil, nil
}
policy, err := ioutil.ReadFile(policyConfigFile)
if err != nil {
return nil, fmt.Errorf("failed to read policy config file %q: %+v", policyConfigFile, err)
}
versionedPolicy := &v1alpha1.DeschedulerPolicy{}
decoder := scheme.Codecs.UniversalDecoder(v1alpha1.SchemeGroupVersion)
if err := runtime.DecodeInto(decoder, policy, versionedPolicy); err != nil {
return nil, fmt.Errorf("failed decoding descheduler's policy config %q: %v", policyConfigFile, err)
}
internalPolicy := &api.DeschedulerPolicy{}
if err := scheme.Scheme.Convert(versionedPolicy, internalPolicy, nil); err != nil {
return nil, fmt.Errorf("failed converting versioned policy to internal policy version: %v", err)
}
return internalPolicy, nil
}

View File

@@ -1,33 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package scheme
import (
"os"
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)
var (
GroupFactoryRegistry = make(announced.APIGroupFactoryRegistry)
Registry = registered.NewOrDie(os.Getenv("DESCHEDULER_API_VERSIONS"))
Scheme = runtime.NewScheme()
Codecs = serializer.NewCodecFactory(Scheme)
)

View File

@@ -1,98 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
clientset "k8s.io/client-go/kubernetes"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions"
podutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/pod"
)
//type creator string
type DuplicatePodsMap map[string][]*v1.Pod
// RemoveDuplicatePods removes the duplicate pods on node. This strategy evicts all duplicate pods on node.
// A pod is said to be a duplicate of other if both of them are from same creator, kind and are within the same
// namespace. As of now, this strategy won't evict daemonsets, mirror pods, critical pods and pods with local storages.
func RemoveDuplicatePods(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, policyGroupVersion string, nodes []*v1.Node, nodepodCount nodePodEvictedCount) {
if !strategy.Enabled {
return
}
deleteDuplicatePods(ds.Client, policyGroupVersion, nodes, ds.DryRun, nodepodCount, ds.MaxNoOfPodsToEvictPerNode)
}
// deleteDuplicatePods evicts the pod from node and returns the count of evicted pods.
func deleteDuplicatePods(client clientset.Interface, policyGroupVersion string, nodes []*v1.Node, dryRun bool, nodepodCount nodePodEvictedCount, maxPodsToEvict int) int {
podsEvicted := 0
for _, node := range nodes {
glog.V(1).Infof("Processing node: %#v", node.Name)
dpm := ListDuplicatePodsOnANode(client, node)
for creator, pods := range dpm {
if len(pods) > 1 {
glog.V(1).Infof("%#v", creator)
// i = 0 does not evict the first pod
for i := 1; i < len(pods); i++ {
if nodepodCount[node]+1 > maxPodsToEvict {
break
}
success, err := evictions.EvictPod(client, pods[i], policyGroupVersion, dryRun)
if !success {
glog.Infof("Error when evicting pod: %#v (%#v)", pods[i].Name, err)
} else {
nodepodCount[node]++
glog.V(1).Infof("Evicted pod: %#v (%#v)", pods[i].Name, err)
}
}
}
}
podsEvicted += nodepodCount[node]
}
return podsEvicted
}
// ListDuplicatePodsOnANode lists duplicate pods on a given node.
func ListDuplicatePodsOnANode(client clientset.Interface, node *v1.Node) DuplicatePodsMap {
pods, err := podutil.ListEvictablePodsOnNode(client, node)
if err != nil {
return nil
}
return FindDuplicatePods(pods)
}
// FindDuplicatePods takes a list of pods and returns a duplicatePodsMap.
func FindDuplicatePods(pods []*v1.Pod) DuplicatePodsMap {
dpm := DuplicatePodsMap{}
for _, pod := range pods {
// Ignoring the error here as in the ListDuplicatePodsOnNode function we call ListEvictablePodsOnNode
// which checks for error.
ownerRefList := podutil.OwnerRef(pod)
for _, ownerRef := range ownerRefList {
// ownerRef doesn't need namespace since the assumption is owner needs to be in the same namespace.
s := strings.Join([]string{ownerRef.Kind, ownerRef.Name}, "/")
dpm[s] = append(dpm[s], pod)
}
}
return dpm
}

View File

@@ -1,85 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"testing"
"github.com/kubernetes-incubator/descheduler/test"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
)
//TODO:@ravisantoshgudimetla This could be made table driven.
func TestFindDuplicatePods(t *testing.T) {
node := test.BuildTestNode("n1", 2000, 3000, 10)
p1 := test.BuildTestPod("p1", 100, 0, node.Name)
p2 := test.BuildTestPod("p2", 100, 0, node.Name)
p3 := test.BuildTestPod("p3", 100, 0, node.Name)
p4 := test.BuildTestPod("p4", 100, 0, node.Name)
p5 := test.BuildTestPod("p5", 100, 0, node.Name)
p6 := test.BuildTestPod("p6", 100, 0, node.Name)
p7 := test.BuildTestPod("p7", 100, 0, node.Name)
p8 := test.BuildTestPod("p8", 100, 0, node.Name)
p9 := test.BuildTestPod("p9", 100, 0, node.Name)
// All the following pods expect for one will be evicted.
p1.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p2.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p3.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p8.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p9.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
// The following 4 pods won't get evicted.
// A daemonset.
p4.ObjectMeta.OwnerReferences = test.GetDaemonSetOwnerRefList()
// A pod with local storage.
p5.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
p5.Spec.Volumes = []v1.Volume{
{
Name: "sample",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{Path: "somePath"},
EmptyDir: &v1.EmptyDirVolumeSource{
SizeLimit: resource.NewQuantity(int64(10), resource.BinarySI)},
},
},
}
// A Mirror Pod.
p6.Annotations = test.GetMirrorPodAnnotation()
// A Critical Pod.
p7.Namespace = "kube-system"
p7.Annotations = test.GetCriticalPodAnnotation()
expectedEvictedPodCount := 2
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.PodList{Items: []v1.Pod{*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9}}, nil
})
fakeClient.Fake.AddReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) {
return true, node, nil
})
npe := nodePodEvictedCount{}
npe[node] = 0
podsEvicted := deleteDuplicatePods(fakeClient, "v1", []*v1.Node{node}, false, npe, 2)
if podsEvicted != expectedEvictedPodCount {
t.Errorf("Unexpected no of pods evicted")
}
}

View File

@@ -1,359 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"sort"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
clientset "k8s.io/client-go/kubernetes"
helper "k8s.io/kubernetes/pkg/api/v1/resource"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions"
nodeutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/node"
podutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/pod"
)
type NodeUsageMap struct {
node *v1.Node
usage api.ResourceThresholds
allPods []*v1.Pod
nonRemovablePods []*v1.Pod
bePods []*v1.Pod
bPods []*v1.Pod
gPods []*v1.Pod
}
type NodePodsMap map[*v1.Node][]*v1.Pod
func LowNodeUtilization(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, evictionPolicyGroupVersion string, nodes []*v1.Node, nodepodCount nodePodEvictedCount) {
if !strategy.Enabled {
return
}
// todo: move to config validation?
// TODO: May be create a struct for the strategy as well, so that we don't have to pass along the all the params?
thresholds := strategy.Params.NodeResourceUtilizationThresholds.Thresholds
if !validateThresholds(thresholds) {
return
}
targetThresholds := strategy.Params.NodeResourceUtilizationThresholds.TargetThresholds
if !validateTargetThresholds(targetThresholds) {
return
}
npm := CreateNodePodsMap(ds.Client, nodes)
lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds)
glog.V(1).Infof("Criteria for a node under utilization: CPU: %v, Mem: %v, Pods: %v",
thresholds[v1.ResourceCPU], thresholds[v1.ResourceMemory], thresholds[v1.ResourcePods])
if len(lowNodes) == 0 {
glog.V(1).Infof("No node is underutilized, nothing to do here, you might tune your thersholds further")
return
}
glog.V(1).Infof("Total number of underutilized nodes: %v", len(lowNodes))
if len(lowNodes) < strategy.Params.NodeResourceUtilizationThresholds.NumberOfNodes {
glog.V(1).Infof("number of nodes underutilized (%v) is less than NumberOfNodes (%v), nothing to do here", len(lowNodes), strategy.Params.NodeResourceUtilizationThresholds.NumberOfNodes)
return
}
if len(lowNodes) == len(nodes) {
glog.V(1).Infof("all nodes are underutilized, nothing to do here")
return
}
if len(targetNodes) == 0 {
glog.V(1).Infof("all nodes are under target utilization, nothing to do here")
return
}
glog.V(1).Infof("Criteria for a node above target utilization: CPU: %v, Mem: %v, Pods: %v",
targetThresholds[v1.ResourceCPU], targetThresholds[v1.ResourceMemory], targetThresholds[v1.ResourcePods])
glog.V(1).Infof("Total number of nodes above target utilization: %v", len(targetNodes))
totalPodsEvicted := evictPodsFromTargetNodes(ds.Client, evictionPolicyGroupVersion, targetNodes, lowNodes, targetThresholds, ds.DryRun, ds.MaxNoOfPodsToEvictPerNode, nodepodCount)
glog.V(1).Infof("Total number of pods evicted: %v", totalPodsEvicted)
}
func validateThresholds(thresholds api.ResourceThresholds) bool {
if thresholds == nil || len(thresholds) == 0 {
glog.V(1).Infof("no resource threshold is configured")
return false
}
for name := range thresholds {
switch name {
case v1.ResourceCPU:
continue
case v1.ResourceMemory:
continue
case v1.ResourcePods:
continue
default:
glog.Errorf("only cpu, memory, or pods thresholds can be specified")
return false
}
}
return true
}
//This function could be merged into above once we are clear.
func validateTargetThresholds(targetThresholds api.ResourceThresholds) bool {
if targetThresholds == nil {
glog.V(1).Infof("no target resource threshold is configured")
return false
} else if _, ok := targetThresholds[v1.ResourcePods]; !ok {
glog.V(1).Infof("no target resource threshold for pods is configured")
return false
}
return true
}
// classifyNodes classifies the nodes into low-utilization or high-utilization nodes. If a node lies between
// low and high thresholds, it is simply ignored.
func classifyNodes(npm NodePodsMap, thresholds api.ResourceThresholds, targetThresholds api.ResourceThresholds) ([]NodeUsageMap, []NodeUsageMap) {
lowNodes, targetNodes := []NodeUsageMap{}, []NodeUsageMap{}
for node, pods := range npm {
usage, allPods, nonRemovablePods, bePods, bPods, gPods := NodeUtilization(node, pods)
nuMap := NodeUsageMap{node, usage, allPods, nonRemovablePods, bePods, bPods, gPods}
// Check if node is underutilized and if we can schedule pods on it.
if !nodeutil.IsNodeUschedulable(node) && IsNodeWithLowUtilization(usage, thresholds) {
glog.V(2).Infof("Node %#v is under utilized with usage: %#v", node.Name, usage)
lowNodes = append(lowNodes, nuMap)
} else if IsNodeAboveTargetUtilization(usage, targetThresholds) {
glog.V(2).Infof("Node %#v is over utilized with usage: %#v", node.Name, usage)
targetNodes = append(targetNodes, nuMap)
} else {
glog.V(2).Infof("Node %#v is appropriately utilized with usage: %#v", node.Name, usage)
}
glog.V(2).Infof("allPods:%v, nonRemovablePods:%v, bePods:%v, bPods:%v, gPods:%v", len(allPods), len(nonRemovablePods), len(bePods), len(bPods), len(gPods))
}
return lowNodes, targetNodes
}
func evictPodsFromTargetNodes(client clientset.Interface, evictionPolicyGroupVersion string, targetNodes, lowNodes []NodeUsageMap, targetThresholds api.ResourceThresholds, dryRun bool, maxPodsToEvict int, nodepodCount nodePodEvictedCount) int {
podsEvicted := 0
SortNodesByUsage(targetNodes)
// upper bound on total number of pods/cpu/memory to be moved
var totalPods, totalCpu, totalMem float64
for _, node := range lowNodes {
nodeCapacity := node.node.Status.Capacity
if len(node.node.Status.Allocatable) > 0 {
nodeCapacity = node.node.Status.Allocatable
}
// totalPods to be moved
podsPercentage := targetThresholds[v1.ResourcePods] - node.usage[v1.ResourcePods]
totalPods += ((float64(podsPercentage) * float64(nodeCapacity.Pods().Value())) / 100)
// totalCPU capacity to be moved
if _, ok := targetThresholds[v1.ResourceCPU]; ok {
cpuPercentage := targetThresholds[v1.ResourceCPU] - node.usage[v1.ResourceCPU]
totalCpu += ((float64(cpuPercentage) * float64(nodeCapacity.Cpu().MilliValue())) / 100)
}
// totalMem capacity to be moved
if _, ok := targetThresholds[v1.ResourceMemory]; ok {
memPercentage := targetThresholds[v1.ResourceMemory] - node.usage[v1.ResourceMemory]
totalMem += ((float64(memPercentage) * float64(nodeCapacity.Memory().Value())) / 100)
}
}
glog.V(1).Infof("Total capacity to be moved: CPU:%v, Mem:%v, Pods:%v", totalCpu, totalMem, totalPods)
glog.V(1).Infof("********Number of pods evicted from each node:***********")
for _, node := range targetNodes {
nodeCapacity := node.node.Status.Capacity
if len(node.node.Status.Allocatable) > 0 {
nodeCapacity = node.node.Status.Allocatable
}
glog.V(3).Infof("evicting pods from node %#v with usage: %#v", node.node.Name, node.usage)
currentPodsEvicted := nodepodCount[node.node]
// evict best effort pods
evictPods(node.bePods, client, evictionPolicyGroupVersion, targetThresholds, nodeCapacity, node.usage, &totalPods, &totalCpu, &totalMem, &currentPodsEvicted, dryRun, maxPodsToEvict)
// evict burstable pods
evictPods(node.bPods, client, evictionPolicyGroupVersion, targetThresholds, nodeCapacity, node.usage, &totalPods, &totalCpu, &totalMem, &currentPodsEvicted, dryRun, maxPodsToEvict)
// evict guaranteed pods
evictPods(node.gPods, client, evictionPolicyGroupVersion, targetThresholds, nodeCapacity, node.usage, &totalPods, &totalCpu, &totalMem, &currentPodsEvicted, dryRun, maxPodsToEvict)
nodepodCount[node.node] = currentPodsEvicted
podsEvicted = podsEvicted + nodepodCount[node.node]
glog.V(1).Infof("%v pods evicted from node %#v with usage %v", nodepodCount[node.node], node.node.Name, node.usage)
}
return podsEvicted
}
func evictPods(inputPods []*v1.Pod,
client clientset.Interface,
evictionPolicyGroupVersion string,
targetThresholds api.ResourceThresholds,
nodeCapacity v1.ResourceList,
nodeUsage api.ResourceThresholds,
totalPods *float64,
totalCpu *float64,
totalMem *float64,
podsEvicted *int,
dryRun bool, maxPodsToEvict int) {
if IsNodeAboveTargetUtilization(nodeUsage, targetThresholds) && (*totalPods > 0 || *totalCpu > 0 || *totalMem > 0) {
onePodPercentage := api.Percentage((float64(1) * 100) / float64(nodeCapacity.Pods().Value()))
for _, pod := range inputPods {
if *podsEvicted+1 > maxPodsToEvict {
break
}
cUsage := helper.GetResourceRequest(pod, v1.ResourceCPU)
mUsage := helper.GetResourceRequest(pod, v1.ResourceMemory)
success, err := evictions.EvictPod(client, pod, evictionPolicyGroupVersion, dryRun)
if !success {
glog.Warningf("Error when evicting pod: %#v (%#v)", pod.Name, err)
} else {
glog.V(3).Infof("Evicted pod: %#v (%#v)", pod.Name, err)
// update remaining pods
*podsEvicted++
nodeUsage[v1.ResourcePods] -= onePodPercentage
*totalPods--
// update remaining cpu
*totalCpu -= float64(cUsage)
nodeUsage[v1.ResourceCPU] -= api.Percentage((float64(cUsage) * 100) / float64(nodeCapacity.Cpu().MilliValue()))
// update remaining memory
*totalMem -= float64(mUsage)
nodeUsage[v1.ResourceMemory] -= api.Percentage(float64(mUsage) / float64(nodeCapacity.Memory().Value()) * 100)
glog.V(3).Infof("updated node usage: %#v", nodeUsage)
// check if node utilization drops below target threshold or required capacity (cpu, memory, pods) is moved
if !IsNodeAboveTargetUtilization(nodeUsage, targetThresholds) || (*totalPods <= 0 && *totalCpu <= 0 && *totalMem <= 0) {
break
}
}
}
}
}
func SortNodesByUsage(nodes []NodeUsageMap) {
sort.Slice(nodes, func(i, j int) bool {
var ti, tj api.Percentage
for name, value := range nodes[i].usage {
if name == v1.ResourceCPU || name == v1.ResourceMemory || name == v1.ResourcePods {
ti += value
}
}
for name, value := range nodes[j].usage {
if name == v1.ResourceCPU || name == v1.ResourceMemory || name == v1.ResourcePods {
tj += value
}
}
// To return sorted in descending order
return ti > tj
})
}
func CreateNodePodsMap(client clientset.Interface, nodes []*v1.Node) NodePodsMap {
npm := NodePodsMap{}
for _, node := range nodes {
pods, err := podutil.ListPodsOnANode(client, node)
if err != nil {
glog.Warningf("node %s will not be processed, error in accessing its pods (%#v)", node.Name, err)
} else {
npm[node] = pods
}
}
return npm
}
func IsNodeAboveTargetUtilization(nodeThresholds api.ResourceThresholds, thresholds api.ResourceThresholds) bool {
for name, nodeValue := range nodeThresholds {
if name == v1.ResourceCPU || name == v1.ResourceMemory || name == v1.ResourcePods {
if value, ok := thresholds[name]; !ok {
continue
} else if nodeValue > value {
return true
}
}
}
return false
}
func IsNodeWithLowUtilization(nodeThresholds api.ResourceThresholds, thresholds api.ResourceThresholds) bool {
for name, nodeValue := range nodeThresholds {
if name == v1.ResourceCPU || name == v1.ResourceMemory || name == v1.ResourcePods {
if value, ok := thresholds[name]; !ok {
continue
} else if nodeValue > value {
return false
}
}
}
return true
}
func NodeUtilization(node *v1.Node, pods []*v1.Pod) (api.ResourceThresholds, []*v1.Pod, []*v1.Pod, []*v1.Pod, []*v1.Pod, []*v1.Pod) {
bePods := []*v1.Pod{}
nonRemovablePods := []*v1.Pod{}
bPods := []*v1.Pod{}
gPods := []*v1.Pod{}
totalReqs := map[v1.ResourceName]resource.Quantity{}
for _, pod := range pods {
// We need to compute the usage of nonRemovablePods unless it is a best effort pod. So, cannot use podutil.ListEvictablePodsOnNode
if !podutil.IsEvictable(pod) {
nonRemovablePods = append(nonRemovablePods, pod)
if podutil.IsBestEffortPod(pod) {
continue
}
} else if podutil.IsBestEffortPod(pod) {
bePods = append(bePods, pod)
continue
} else if podutil.IsBurstablePod(pod) {
bPods = append(bPods, pod)
} else {
gPods = append(gPods, pod)
}
req, _ := helper.PodRequestsAndLimits(pod)
for name, quantity := range req {
if name == v1.ResourceCPU || name == v1.ResourceMemory {
if value, ok := totalReqs[name]; !ok {
totalReqs[name] = *quantity.Copy()
} else {
value.Add(quantity)
totalReqs[name] = value
}
}
}
}
nodeCapacity := node.Status.Capacity
if len(node.Status.Allocatable) > 0 {
nodeCapacity = node.Status.Allocatable
}
usage := api.ResourceThresholds{}
totalCPUReq := totalReqs[v1.ResourceCPU]
totalMemReq := totalReqs[v1.ResourceMemory]
totalPods := len(pods)
usage[v1.ResourceCPU] = api.Percentage((float64(totalCPUReq.MilliValue()) * 100) / float64(nodeCapacity.Cpu().MilliValue()))
usage[v1.ResourceMemory] = api.Percentage(float64(totalMemReq.Value()) / float64(nodeCapacity.Memory().Value()) * 100)
usage[v1.ResourcePods] = api.Percentage((float64(totalPods) * 100) / float64(nodeCapacity.Pods().Value()))
return usage, pods, nonRemovablePods, bePods, bPods, gPods
}

View File

@@ -1,179 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"fmt"
"strings"
"testing"
"github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/test"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
)
// TODO: Make this table driven.
func TestLowNodeUtilization(t *testing.T) {
var thresholds = make(api.ResourceThresholds)
var targetThresholds = make(api.ResourceThresholds)
thresholds[v1.ResourceCPU] = 30
thresholds[v1.ResourcePods] = 30
targetThresholds[v1.ResourceCPU] = 50
targetThresholds[v1.ResourcePods] = 50
n1 := test.BuildTestNode("n1", 4000, 3000, 9)
n2 := test.BuildTestNode("n2", 4000, 3000, 10)
n3 := test.BuildTestNode("n3", 4000, 3000, 10)
// Making n3 node unschedulable so that it won't counted in lowUtilized nodes list.
n3.Spec.Unschedulable = true
p1 := test.BuildTestPod("p1", 400, 0, n1.Name)
p2 := test.BuildTestPod("p2", 400, 0, n1.Name)
p3 := test.BuildTestPod("p3", 400, 0, n1.Name)
p4 := test.BuildTestPod("p4", 400, 0, n1.Name)
p5 := test.BuildTestPod("p5", 400, 0, n1.Name)
// These won't be evicted.
p6 := test.BuildTestPod("p6", 400, 0, n1.Name)
p7 := test.BuildTestPod("p7", 400, 0, n1.Name)
p8 := test.BuildTestPod("p8", 400, 0, n1.Name)
p1.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p2.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p3.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p4.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
p5.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
// The following 4 pods won't get evicted.
// A daemonset.
p6.ObjectMeta.OwnerReferences = test.GetDaemonSetOwnerRefList()
// A pod with local storage.
p7.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
p7.Spec.Volumes = []v1.Volume{
{
Name: "sample",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{Path: "somePath"},
EmptyDir: &v1.EmptyDirVolumeSource{
SizeLimit: resource.NewQuantity(int64(10), resource.BinarySI)},
},
},
}
// A Mirror Pod.
p7.Annotations = test.GetMirrorPodAnnotation()
// A Critical Pod.
p8.Namespace = "kube-system"
p8.Annotations = test.GetCriticalPodAnnotation()
p9 := test.BuildTestPod("p9", 400, 0, n1.Name)
p9.ObjectMeta.OwnerReferences = test.GetReplicaSetOwnerRefList()
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {
list := action.(core.ListAction)
fieldString := list.GetListRestrictions().Fields.String()
if strings.Contains(fieldString, "n1") {
return true, &v1.PodList{Items: []v1.Pod{*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8}}, nil
}
if strings.Contains(fieldString, "n2") {
return true, &v1.PodList{Items: []v1.Pod{*p9}}, nil
}
if strings.Contains(fieldString, "n3") {
return true, &v1.PodList{Items: []v1.Pod{}}, nil
}
return true, nil, fmt.Errorf("Failed to list: %v", list)
})
fakeClient.Fake.AddReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) {
getAction := action.(core.GetAction)
switch getAction.GetName() {
case n1.Name:
return true, n1, nil
case n2.Name:
return true, n2, nil
case n3.Name:
return true, n3, nil
}
return true, nil, fmt.Errorf("Wrong node: %v", getAction.GetName())
})
expectedPodsEvicted := 3
npm := CreateNodePodsMap(fakeClient, []*v1.Node{n1, n2, n3})
lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds)
if len(lowNodes) != 1 {
t.Errorf("After ignoring unschedulable nodes, expected only one node to be under utilized.")
}
npe := nodePodEvictedCount{}
npe[n1] = 0
npe[n2] = 0
npe[n3] = 0
podsEvicted := evictPodsFromTargetNodes(fakeClient, "v1", targetNodes, lowNodes, targetThresholds, false, 3, npe)
if expectedPodsEvicted != podsEvicted {
t.Errorf("Expected %#v pods to be evicted but %#v got evicted", expectedPodsEvicted, podsEvicted)
}
}
func TestValidateThresholds(t *testing.T) {
tests := []struct {
name string
input api.ResourceThresholds
succeed bool
}{
{
name: "passing nil map for threshold",
input: nil,
succeed: false,
},
{
name: "passing no threshold",
input: api.ResourceThresholds{},
succeed: false,
},
{
name: "passing unsupported resource name",
input: api.ResourceThresholds{
v1.ResourceCPU: 40,
v1.ResourceStorage: 25.5,
},
succeed: false,
},
{
name: "passing invalid resource name",
input: api.ResourceThresholds{
v1.ResourceCPU: 40,
"coolResource": 42.0,
},
succeed: false,
},
{
name: "passing a valid threshold with cpu, memory and pods",
input: api.ResourceThresholds{
v1.ResourceCPU: 20,
v1.ResourceMemory: 30,
v1.ResourcePods: 40,
},
succeed: true,
},
}
for _, test := range tests {
isValid := validateThresholds(test.input)
if isValid != test.succeed {
t.Errorf("expected validity of threshold: %#v\nto be %v but got %v instead", test.input, test.succeed, isValid)
}
}
}

View File

@@ -1,74 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"github.com/golang/glog"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions"
nodeutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/node"
podutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/pod"
"k8s.io/api/core/v1"
)
func RemovePodsViolatingNodeAffinity(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, evictionPolicyGroupVersion string, nodes []*v1.Node, nodePodCount nodePodEvictedCount) {
evictionCount := removePodsViolatingNodeAffinityCount(ds, strategy, evictionPolicyGroupVersion, nodes, nodePodCount, ds.MaxNoOfPodsToEvictPerNode)
glog.V(1).Infof("Evicted %v pods", evictionCount)
}
func removePodsViolatingNodeAffinityCount(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, evictionPolicyGroupVersion string, nodes []*v1.Node, nodepodCount nodePodEvictedCount, maxPodsToEvict int) int {
evictedPodCount := 0
if !strategy.Enabled {
return evictedPodCount
}
for _, nodeAffinity := range strategy.Params.NodeAffinityType {
glog.V(2).Infof("Executing for nodeAffinityType: %v", nodeAffinity)
switch nodeAffinity {
case "requiredDuringSchedulingIgnoredDuringExecution":
for _, node := range nodes {
glog.V(1).Infof("Processing node: %#v\n", node.Name)
pods, err := podutil.ListEvictablePodsOnNode(ds.Client, node)
if err != nil {
glog.Errorf("failed to get pods from %v: %v", node.Name, err)
}
for _, pod := range pods {
if nodepodCount[node]+1 > maxPodsToEvict {
break
}
if pod.Spec.Affinity != nil && pod.Spec.Affinity.NodeAffinity != nil && pod.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
if !nodeutil.PodFitsCurrentNode(pod, node) && nodeutil.PodFitsAnyNode(pod, nodes) {
glog.V(1).Infof("Evicting pod: %v", pod.Name)
evictions.EvictPod(ds.Client, pod, evictionPolicyGroupVersion, false)
nodepodCount[node]++
}
}
}
evictedPodCount += nodepodCount[node]
}
default:
glog.Errorf("invalid nodeAffinityType: %v", nodeAffinity)
return evictedPodCount
}
}
return evictedPodCount
}

View File

@@ -1,184 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"testing"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/test"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
)
func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
requiredDuringSchedulingIgnoredDuringExecutionStrategy := api.DeschedulerStrategy{
Enabled: true,
Params: api.StrategyParameters{
NodeAffinityType: []string{
"requiredDuringSchedulingIgnoredDuringExecution",
},
},
}
nodeLabelKey := "kubernetes.io/desiredNode"
nodeLabelValue := "yes"
nodeWithLabels := test.BuildTestNode("nodeWithLabels", 2000, 3000, 10)
nodeWithLabels.Labels[nodeLabelKey] = nodeLabelValue
nodeWithoutLabels := test.BuildTestNode("nodeWithoutLabels", 2000, 3000, 10)
unschedulableNodeWithLabels := test.BuildTestNode("unschedulableNodeWithLabels", 2000, 3000, 10)
nodeWithLabels.Labels[nodeLabelKey] = nodeLabelValue
unschedulableNodeWithLabels.Spec.Unschedulable = true
addPodsToNode := func(node *v1.Node) []v1.Pod {
podWithNodeAffinity := test.BuildTestPod("podWithNodeAffinity", 100, 0, node.Name)
podWithNodeAffinity.Spec.Affinity = &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: nodeLabelKey,
Operator: "In",
Values: []string{
nodeLabelValue,
},
},
},
},
},
},
},
}
pod1 := test.BuildTestPod("pod1", 100, 0, node.Name)
pod2 := test.BuildTestPod("pod2", 100, 0, node.Name)
podWithNodeAffinity.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
pod1.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
pod2.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
return []v1.Pod{
*podWithNodeAffinity,
*pod1,
*pod2,
}
}
tests := []struct {
description string
nodes []*v1.Node
pods []v1.Pod
strategy api.DeschedulerStrategy
expectedEvictedPodCount int
npe nodePodEvictedCount
maxPodsToEvict int
}{
{
description: "Strategy disabled, should not evict any pods",
strategy: api.DeschedulerStrategy{
Enabled: false,
Params: api.StrategyParameters{
NodeAffinityType: []string{
"requiredDuringSchedulingIgnoredDuringExecution",
},
},
},
expectedEvictedPodCount: 0,
pods: addPodsToNode(nodeWithoutLabels),
nodes: []*v1.Node{nodeWithoutLabels, nodeWithLabels},
npe: nodePodEvictedCount{nodeWithoutLabels: 0, nodeWithLabels: 0},
maxPodsToEvict: 0,
},
{
description: "Invalid strategy type, should not evict any pods",
strategy: api.DeschedulerStrategy{
Enabled: true,
Params: api.StrategyParameters{
NodeAffinityType: []string{
"requiredDuringSchedulingRequiredDuringExecution",
},
},
},
expectedEvictedPodCount: 0,
pods: addPodsToNode(nodeWithoutLabels),
nodes: []*v1.Node{nodeWithoutLabels, nodeWithLabels},
npe: nodePodEvictedCount{nodeWithoutLabels: 0, nodeWithLabels: 0},
maxPodsToEvict: 0,
},
{
description: "Pod is correctly scheduled on node, no eviction expected",
strategy: requiredDuringSchedulingIgnoredDuringExecutionStrategy,
expectedEvictedPodCount: 0,
pods: addPodsToNode(nodeWithLabels),
nodes: []*v1.Node{nodeWithLabels},
npe: nodePodEvictedCount{nodeWithLabels: 0},
maxPodsToEvict: 0,
},
{
description: "Pod is scheduled on node without matching labels, another schedulable node available, should be evicted",
expectedEvictedPodCount: 1,
strategy: requiredDuringSchedulingIgnoredDuringExecutionStrategy,
pods: addPodsToNode(nodeWithoutLabels),
nodes: []*v1.Node{nodeWithoutLabels, nodeWithLabels},
npe: nodePodEvictedCount{nodeWithoutLabels: 0, nodeWithLabels: 0},
maxPodsToEvict: 1,
},
{
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxPodsToEvict set to 0, should not be evicted",
expectedEvictedPodCount: 0,
strategy: requiredDuringSchedulingIgnoredDuringExecutionStrategy,
pods: addPodsToNode(nodeWithoutLabels),
nodes: []*v1.Node{nodeWithoutLabels, nodeWithLabels},
npe: nodePodEvictedCount{nodeWithoutLabels: 0, nodeWithLabels: 0},
maxPodsToEvict: 0,
},
{
description: "Pod is scheduled on node without matching labels, but no node where pod fits is available, should not evict",
expectedEvictedPodCount: 0,
strategy: requiredDuringSchedulingIgnoredDuringExecutionStrategy,
pods: addPodsToNode(nodeWithoutLabels),
nodes: []*v1.Node{nodeWithoutLabels, unschedulableNodeWithLabels},
npe: nodePodEvictedCount{nodeWithoutLabels: 0, unschedulableNodeWithLabels: 0},
maxPodsToEvict: 0,
},
}
for _, tc := range tests {
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.PodList{Items: tc.pods}, nil
})
ds := options.DeschedulerServer{
Client: fakeClient,
}
actualEvictedPodCount := removePodsViolatingNodeAffinityCount(&ds, tc.strategy, "v1", tc.nodes, tc.npe, tc.maxPodsToEvict)
if actualEvictedPodCount != tc.expectedEvictedPodCount {
t.Errorf("Test %#v failed, expected %v pod evictions, but got %v pod evictions\n", tc.description, tc.expectedEvictedPodCount, actualEvictedPodCount)
}
}
}

View File

@@ -1,105 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions"
podutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/pod"
"github.com/golang/glog"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
priorityutil "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/priorities/util"
)
// RemovePodsViolatingInterPodAntiAffinity with elimination strategy
func RemovePodsViolatingInterPodAntiAffinity(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, policyGroupVersion string, nodes []*v1.Node, nodePodCount nodePodEvictedCount) {
if !strategy.Enabled {
return
}
removePodsWithAffinityRules(ds.Client, policyGroupVersion, nodes, ds.DryRun, nodePodCount, ds.MaxNoOfPodsToEvictPerNode)
}
// removePodsWithAffinityRules evicts pods on the node which are having a pod affinity rules.
func removePodsWithAffinityRules(client clientset.Interface, policyGroupVersion string, nodes []*v1.Node, dryRun bool, nodePodCount nodePodEvictedCount, maxPodsToEvict int) int {
podsEvicted := 0
for _, node := range nodes {
glog.V(1).Infof("Processing node: %#v\n", node.Name)
pods, err := podutil.ListEvictablePodsOnNode(client, node)
if err != nil {
return 0
}
totalPods := len(pods)
for i := 0; i < totalPods; i++ {
if nodePodCount[node]+1 > maxPodsToEvict {
break
}
if checkPodsWithAntiAffinityExist(pods[i], pods) {
success, err := evictions.EvictPod(client, pods[i], policyGroupVersion, dryRun)
if !success {
glog.Infof("Error when evicting pod: %#v (%#v)\n", pods[i].Name, err)
} else {
nodePodCount[node]++
glog.V(1).Infof("Evicted pod: %#v (%#v)\n because of existing anti-affinity", pods[i].Name, err)
// Since the current pod is evicted all other pods which have anti-affinity with this
// pod need not be evicted.
// Update pods.
pods = append(pods[:i], pods[i+1:]...)
i--
totalPods--
}
}
}
podsEvicted += nodePodCount[node]
}
return podsEvicted
}
// checkPodsWithAntiAffinityExist checks if there are other pods on the node that the current pod cannot tolerate.
func checkPodsWithAntiAffinityExist(pod *v1.Pod, pods []*v1.Pod) bool {
affinity := pod.Spec.Affinity
if affinity != nil && affinity.PodAntiAffinity != nil {
for _, term := range getPodAntiAffinityTerms(affinity.PodAntiAffinity) {
namespaces := priorityutil.GetNamespacesFromPodAffinityTerm(pod, &term)
selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector)
if err != nil {
glog.Infof("%v", err)
return false
}
for _, existingPod := range pods {
if existingPod.Name != pod.Name && priorityutil.PodMatchesTermsNamespaceAndSelector(existingPod, namespaces, selector) {
return true
}
}
}
}
return false
}
// getPodAntiAffinityTerms gets the antiaffinity terms for the given pod.
func getPodAntiAffinityTerms(podAntiAffinity *v1.PodAntiAffinity) (terms []v1.PodAffinityTerm) {
if podAntiAffinity != nil {
if len(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
terms = podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution
}
}
return terms
}

View File

@@ -1,94 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"testing"
"github.com/kubernetes-incubator/descheduler/test"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
)
func TestPodAntiAffinity(t *testing.T) {
node := test.BuildTestNode("n1", 2000, 3000, 10)
p1 := test.BuildTestPod("p1", 100, 0, node.Name)
p2 := test.BuildTestPod("p2", 100, 0, node.Name)
p3 := test.BuildTestPod("p3", 100, 0, node.Name)
p3.Labels = map[string]string{"foo": "bar"}
p1.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
p2.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
p3.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList()
p1.Spec.Affinity = &v1.Affinity{
PodAntiAffinity: &v1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
{
LabelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "foo",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"bar"},
},
},
},
TopologyKey: "region",
},
},
},
}
p3.Spec.Affinity = &v1.Affinity{
PodAntiAffinity: &v1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
{
LabelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "foo",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"bar"},
},
},
},
TopologyKey: "region",
},
},
},
}
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.PodList{Items: []v1.Pod{*p1, *p2, *p3}}, nil
})
fakeClient.Fake.AddReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) {
return true, node, nil
})
npe := nodePodEvictedCount{}
npe[node] = 0
expectedEvictedPodCount := 0
podsEvicted := removePodsWithAffinityRules(fakeClient, "v1", []*v1.Node{node}, false, npe, 0)
if podsEvicted != expectedEvictedPodCount {
t.Errorf("Unexpected no of pods evicted")
}
expectedEvictedPodCount = 1
podsEvicted = removePodsWithAffinityRules(fakeClient, "v1", []*v1.Node{node}, false, npe, 1)
if podsEvicted != expectedEvictedPodCount {
t.Errorf("Unexpected no of pods evicted")
}
}

View File

@@ -1,37 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strategies
import (
"k8s.io/api/core/v1"
)
// This file contains the datastructures, types & functions needed by all the strategies so that we don't have
// to compute them again in each strategy.
// nodePodEvictedCount keeps count of pods evicted on node. This is used in conjunction with strategies to
type nodePodEvictedCount map[*v1.Node]int
// InitializeNodePodCount initializes the nodePodCount.
func InitializeNodePodCount(nodeList []*v1.Node) nodePodEvictedCount {
var nodePodCount = make(nodePodEvictedCount)
for _, node := range nodeList {
// Initialize podsEvicted till now with 0.
nodePodCount[node] = 0
}
return nodePodCount
}

View File

@@ -1,94 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
"fmt"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
)
// The following code has been copied from predicates package to avoid the
// huge vendoring issues, mostly copied from
// k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/
// Some minor changes have been made to ease the imports, but most of the code
// remains untouched
// PodMatchNodeSelector checks if a pod node selector matches the node label.
func PodMatchNodeSelector(pod *v1.Pod, node *v1.Node) (bool, error) {
if node == nil {
return false, fmt.Errorf("node not found")
}
if podMatchesNodeLabels(pod, node) {
return true, nil
}
return false, nil
}
// The pod can only schedule onto nodes that satisfy requirements in both NodeAffinity and nodeSelector.
func podMatchesNodeLabels(pod *v1.Pod, node *v1.Node) bool {
// Check if node.Labels match pod.Spec.NodeSelector.
if len(pod.Spec.NodeSelector) > 0 {
selector := labels.SelectorFromSet(pod.Spec.NodeSelector)
if !selector.Matches(labels.Set(node.Labels)) {
return false
}
}
// 1. nil NodeSelector matches all nodes (i.e. does not filter out any nodes)
// 2. nil []NodeSelectorTerm (equivalent to non-nil empty NodeSelector) matches no nodes
// 3. zero-length non-nil []NodeSelectorTerm matches no nodes also, just for simplicity
// 4. nil []NodeSelectorRequirement (equivalent to non-nil empty NodeSelectorTerm) matches no nodes
// 5. zero-length non-nil []NodeSelectorRequirement matches no nodes also, just for simplicity
// 6. non-nil empty NodeSelectorRequirement is not allowed
affinity := pod.Spec.Affinity
if affinity != nil && affinity.NodeAffinity != nil {
nodeAffinity := affinity.NodeAffinity
// if no required NodeAffinity requirements, will do no-op, means select all nodes.
if nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution == nil {
return true
}
// Match node selector for requiredDuringSchedulingIgnoredDuringExecution.
if nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
nodeSelectorTerms := nodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms
glog.V(10).Infof("Match for RequiredDuringSchedulingIgnoredDuringExecution node selector terms %+v", nodeSelectorTerms)
return nodeMatchesNodeSelectorTerms(node, nodeSelectorTerms)
}
}
return true
}
// nodeMatchesNodeSelectorTerms checks if a node's labels satisfy a list of node selector terms,
// terms are ORed, and an empty list of terms will match nothing.
func nodeMatchesNodeSelectorTerms(node *v1.Node, nodeSelectorTerms []v1.NodeSelectorTerm) bool {
for _, req := range nodeSelectorTerms {
nodeSelector, err := v1helper.NodeSelectorRequirementsAsSelector(req.MatchExpressions)
if err != nil {
glog.V(10).Infof("Failed to parse MatchExpressions: %+v, regarding as not match.", req.MatchExpressions)
return false
}
if nodeSelector.Matches(labels.Set(node.Labels)) {
return true
}
}
return false
}

View File

@@ -1,17 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils

View File

@@ -1,156 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"github.com/golang/glog"
"testing"
"time"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
deschedulerapi "github.com/kubernetes-incubator/descheduler/pkg/api"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/client"
eutils "github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions/utils"
nodeutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/node"
podutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/pod"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/strategies"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/api/testapi"
)
func MakePodSpec() v1.PodSpec {
return v1.PodSpec{
Containers: []v1.Container{{
Name: "pause",
Image: "kubernetes/pause",
Ports: []v1.ContainerPort{{ContainerPort: 80}},
Resources: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("100m"),
v1.ResourceMemory: resource.MustParse("500Mi"),
},
Requests: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("100m"),
v1.ResourceMemory: resource.MustParse("500Mi"),
},
},
}},
}
}
// RcByNameContainer returns a ReplicationControoler with specified name and container
func RcByNameContainer(name string, replicas int32, labels map[string]string, gracePeriod *int64) *v1.ReplicationController {
zeroGracePeriod := int64(0)
// Add "name": name to the labels, overwriting if it exists.
labels["name"] = name
if gracePeriod == nil {
gracePeriod = &zeroGracePeriod
}
return &v1.ReplicationController{
TypeMeta: metav1.TypeMeta{
Kind: "ReplicationController",
APIVersion: testapi.Groups[v1.GroupName].GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1.ReplicationControllerSpec{
Replicas: func(i int32) *int32 { return &i }(replicas),
Selector: map[string]string{
"name": name,
},
Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: MakePodSpec(),
},
},
}
}
// startEndToEndForLowNodeUtilization tests the lownode utilization strategy.
func startEndToEndForLowNodeUtilization(clientset clientset.Interface) {
var thresholds = make(deschedulerapi.ResourceThresholds)
var targetThresholds = make(deschedulerapi.ResourceThresholds)
thresholds[v1.ResourceMemory] = 20
thresholds[v1.ResourcePods] = 20
thresholds[v1.ResourceCPU] = 85
targetThresholds[v1.ResourceMemory] = 20
targetThresholds[v1.ResourcePods] = 20
targetThresholds[v1.ResourceCPU] = 90
// Run descheduler.
evictionPolicyGroupVersion, err := eutils.SupportEviction(clientset)
if err != nil || len(evictionPolicyGroupVersion) == 0 {
glog.Fatalf("%v", err)
}
stopChannel := make(chan struct{})
nodes, err := nodeutil.ReadyNodes(clientset, "", stopChannel)
if err != nil {
glog.Fatalf("%v", err)
}
nodeUtilizationThresholds := deschedulerapi.NodeResourceUtilizationThresholds{Thresholds: thresholds, TargetThresholds: targetThresholds}
nodeUtilizationStrategyParams := deschedulerapi.StrategyParameters{NodeResourceUtilizationThresholds: nodeUtilizationThresholds}
lowNodeUtilizationStrategy := deschedulerapi.DeschedulerStrategy{Enabled: true, Params: nodeUtilizationStrategyParams}
ds := &options.DeschedulerServer{Client: clientset}
nodePodCount := strategies.InitializeNodePodCount(nodes)
strategies.LowNodeUtilization(ds, lowNodeUtilizationStrategy, evictionPolicyGroupVersion, nodes, nodePodCount)
time.Sleep(10 * time.Second)
return
}
func TestE2E(t *testing.T) {
// If we have reached here, it means cluster would have been already setup and the kubeconfig file should
// be in /tmp directory.
clientSet, err := client.CreateClient("/tmp/admin.conf")
if err != nil {
t.Errorf("Error during client creation with %v", err)
}
nodeList, err := clientSet.Core().Nodes().List(metav1.ListOptions{})
if err != nil {
t.Errorf("Error listing node with %v", err)
}
// Assumption: We would have 3 node cluster by now. Kubeadm brings all the master components onto master node.
// So, the last node would have least utilization.
leastLoadedNode := nodeList.Items[2]
rc := RcByNameContainer("test-rc", int32(15), map[string]string{"test": "app"}, nil)
_, err = clientSet.CoreV1().ReplicationControllers("default").Create(rc)
if err != nil {
t.Errorf("Error creating deployment %v", err)
}
podsOnleastUtilizedNode, err := podutil.ListPodsOnANode(clientSet, &leastLoadedNode)
if err != nil {
t.Errorf("Error listing pods on a node %v", err)
}
podsBefore := len(podsOnleastUtilizedNode)
t.Log("Eviction of pods starting")
startEndToEndForLowNodeUtilization(clientSet)
podsOnleastUtilizedNode, err = podutil.ListPodsOnANode(clientSet, &leastLoadedNode)
if err != nil {
t.Errorf("Error listing pods on a node %v", err)
}
podsAfter := len(podsOnleastUtilizedNode)
if podsBefore > podsAfter {
t.Fatalf("We should have see more pods on this node as per kubeadm's way of installing %v, %v", podsBefore, podsAfter)
}
}

View File

@@ -1,20 +0,0 @@
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#!/bin/bash
# This just run e2e tests.
PRJ_PREFIX="github.com/${REPO_ORG:-kubernetes-incubator}/descheduler"
go test ${PRJ_PREFIX}/test/e2e/ -v

View File

@@ -1,20 +0,0 @@
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#!/bin/bash
# This just run unit-tests. Ignoring the current directory so as to avoid running e2e tests.
PRJ_PREFIX="github.com/${REPO_ORG:-kubernetes-incubator}/descheduler"
go test $(go list ${PRJ_PREFIX}/... | grep -v ${PRJ_PREFIX}/vendor/| grep -v ${PRJ_PREFIX}/test/)

View File

@@ -1,120 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"fmt"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// BuildTestPod creates a test pod with given parameters.
func BuildTestPod(name string, cpu int64, memory int64, nodeName string) *v1.Pod {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: name,
SelfLink: fmt.Sprintf("/api/v1/namespaces/default/pods/%s", name),
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{},
},
},
},
NodeName: nodeName,
},
}
if cpu >= 0 {
pod.Spec.Containers[0].Resources.Requests[v1.ResourceCPU] = *resource.NewMilliQuantity(cpu, resource.DecimalSI)
}
if memory >= 0 {
pod.Spec.Containers[0].Resources.Requests[v1.ResourceMemory] = *resource.NewQuantity(memory, resource.DecimalSI)
}
return pod
}
// GetMirrorPodAnnotation returns the annotation needed for mirror pod.
func GetMirrorPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
"kubernetes.io/config.source": "api",
"kubernetes.io/config.mirror": "mirror",
}
}
// GetNormalPodOwnerRefList returns the ownerRef needed for a pod.
func GetNormalPodOwnerRefList() []metav1.OwnerReference {
ownerRefList := make([]metav1.OwnerReference, 0)
ownerRefList = append(ownerRefList, metav1.OwnerReference{Kind: "Pod", APIVersion: "v1"})
return ownerRefList
}
// GetReplicaSetOwnerRefList returns the ownerRef needed for replicaset pod.
func GetReplicaSetOwnerRefList() []metav1.OwnerReference {
ownerRefList := make([]metav1.OwnerReference, 0)
ownerRefList = append(ownerRefList, metav1.OwnerReference{Kind: "ReplicaSet", APIVersion: "v1"})
return ownerRefList
}
// GetDaemonSetOwnerRefList returns the ownerRef needed for daemonset pod.
func GetDaemonSetOwnerRefList() []metav1.OwnerReference {
ownerRefList := make([]metav1.OwnerReference, 0)
ownerRefList = append(ownerRefList, metav1.OwnerReference{Kind: "DaemonSet", APIVersion: "v1"})
return ownerRefList
}
// GetCriticalPodAnnotation returns the annotation needed for critical pod.
func GetCriticalPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
"scheduler.alpha.kubernetes.io/critical-pod": "",
}
}
// BuildTestNode creates a node with specified capacity.
func BuildTestNode(name string, millicpu int64, mem int64, pods int64) *v1.Node {
node := &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: name,
SelfLink: fmt.Sprintf("/api/v1/nodes/%s", name),
Labels: map[string]string{},
},
Status: v1.NodeStatus{
Capacity: v1.ResourceList{
v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI),
v1.ResourceCPU: *resource.NewMilliQuantity(millicpu, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(mem, resource.DecimalSI),
},
Allocatable: v1.ResourceList{
v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI),
v1.ResourceCPU: *resource.NewMilliQuantity(millicpu, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(mem, resource.DecimalSI),
},
Phase: v1.NodeRunning,
Conditions: []v1.NodeCondition{
{Type: v1.NodeReady, Status: v1.ConditionTrue},
},
},
}
return node
}

View File

@@ -1,5 +0,0 @@
*.sublime-*
.DS_Store
*.swp
*.swo
tags

View File

@@ -1,7 +0,0 @@
language: go
go:
- 1.4
- 1.5
- 1.6
- tip

View File

@@ -1,12 +0,0 @@
Copyright (c) 2012, Martin Angers
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,185 +0,0 @@
# Purell
Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know...
Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
[![build status](https://secure.travis-ci.org/PuerkitoBio/purell.png)](http://travis-ci.org/PuerkitoBio/purell)
## Install
`go get github.com/PuerkitoBio/purell`
## Changelog
* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
* **v0.2.0** : Add benchmarks, Attempt IDN support.
* **v0.1.0** : Initial release.
## Examples
From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
```go
package purell
import (
"fmt"
"net/url"
)
func ExampleNormalizeURLString() {
if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
panic(err)
} else {
fmt.Print(normalized)
}
// Output: http://somewebsite.com:80/Amazing%3F/url/
}
func ExampleMustNormalizeURLString() {
normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
FlagsUnsafeGreedy)
fmt.Print(normalized)
// Output: http://somewebsite.com/Amazing%FA/url
}
func ExampleNormalizeURL() {
if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
panic(err)
} else {
normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
fmt.Print(normalized)
}
// Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
}
```
## API
As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags:
```go
const (
// Safe normalizations
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
FlagLowercaseHost // http://HOST -> http://host
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
FlagRemoveDefaultPort // http://host:80 -> http://host
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
// Usually safe normalizations
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
// Unsafe normalizations
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
FlagRemoveFragment // http://host/path#fragment -> http://host/path
FlagForceHTTP // https://host -> http://host
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
FlagRemoveWWW // http://www.host/ -> http://host/
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
// Normalizations not in the wikipedia article, required to cover tests cases
// submitted by jehiah
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
// Convenience set of safe normalizations
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
// Convenience set of usually safe normalizations (includes FlagsSafe)
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
// Convenience set of all available flags
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
)
```
For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set.
The [full godoc reference is available on gopkgdoc][godoc].
Some things to note:
* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it.
* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
- %24 -> $
- %26 -> &
- %2B-%3B -> +,-./0123456789:;
- %3D -> =
- %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
- %5F -> _
- %61-%7A -> abcdefghijklmnopqrstuvwxyz
- %7E -> ~
* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell.
* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object.
### Safe vs Usually Safe vs Unsafe
Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between.
Consider the following URL:
`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
Normalizing with the `FlagsSafe` gives:
`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
With the `FlagsUsuallySafeGreedy`:
`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
And with `FlagsUnsafeGreedy`:
`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
## TODOs
* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
## Thanks / Contributions
@rogpeppe
@jehiah
@opennota
@pchristopher1275
@zenovich
## License
The [BSD 3-Clause license][bsd].
[bsd]: http://opensource.org/licenses/BSD-3-Clause
[wiki]: http://en.wikipedia.org/wiki/URL_normalization
[rfc]: http://tools.ietf.org/html/rfc3986#section-6
[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell
[pr5]: https://github.com/PuerkitoBio/purell/pull/5
[iss7]: https://github.com/PuerkitoBio/purell/issues/7

View File

@@ -1,57 +0,0 @@
package purell
import (
"testing"
)
var (
safeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/..//?"
usuallySafeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/"
unsafeUrl = "HttPS://..www.iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allDWORDUrl = "HttPS://1113982867:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allOctalUrl = "HttPS://0102.0146.07.0223:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allHexUrl = "HttPS://0x42660793:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
allCombinedUrl = "HttPS://..0x42660793.:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
)
func BenchmarkSafe(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(safeUrl, FlagsSafe)
}
}
func BenchmarkUsuallySafe(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(usuallySafeUrl, FlagsUsuallySafeGreedy)
}
}
func BenchmarkUnsafe(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(unsafeUrl, FlagsUnsafeGreedy)
}
}
func BenchmarkAllDWORD(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allDWORDUrl, FlagsAllGreedy)
}
}
func BenchmarkAllOctal(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allOctalUrl, FlagsAllGreedy)
}
}
func BenchmarkAllHex(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allHexUrl, FlagsAllGreedy)
}
}
func BenchmarkAllCombined(b *testing.B) {
for i := 0; i < b.N; i++ {
NormalizeURLString(allCombinedUrl, FlagsAllGreedy)
}
}

View File

@@ -1,9 +0,0 @@
PASS
BenchmarkSafe 500000 6131 ns/op
BenchmarkUsuallySafe 200000 7864 ns/op
BenchmarkUnsafe 100000 28560 ns/op
BenchmarkAllDWORD 50000 38722 ns/op
BenchmarkAllOctal 50000 40941 ns/op
BenchmarkAllHex 50000 44063 ns/op
BenchmarkAllCombined 50000 33613 ns/op
ok github.com/PuerkitoBio/purell 17.404s

View File

@@ -1,35 +0,0 @@
package purell
import (
"fmt"
"net/url"
)
func ExampleNormalizeURLString() {
if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
panic(err)
} else {
fmt.Print(normalized)
}
// Output: http://somewebsite.com:80/Amazing%3F/url/
}
func ExampleMustNormalizeURLString() {
normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
FlagsUnsafeGreedy)
fmt.Print(normalized)
// Output: http://somewebsite.com/Amazing%FA/url
}
func ExampleNormalizeURL() {
if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
panic(err)
} else {
normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
fmt.Print(normalized)
}
// Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
}

View File

@@ -1,375 +0,0 @@
/*
Package purell offers URL normalization as described on the wikipedia page:
http://en.wikipedia.org/wiki/URL_normalization
*/
package purell
import (
"bytes"
"fmt"
"net/url"
"regexp"
"sort"
"strconv"
"strings"
"github.com/PuerkitoBio/urlesc"
"golang.org/x/net/idna"
"golang.org/x/text/secure/precis"
"golang.org/x/text/unicode/norm"
)
// A set of normalization flags determines how a URL will
// be normalized.
type NormalizationFlags uint
const (
// Safe normalizations
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
FlagLowercaseHost // http://HOST -> http://host
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
FlagRemoveDefaultPort // http://host:80 -> http://host
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
// Usually safe normalizations
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
// Unsafe normalizations
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
FlagRemoveFragment // http://host/path#fragment -> http://host/path
FlagForceHTTP // https://host -> http://host
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
FlagRemoveWWW // http://www.host/ -> http://host/
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
// Normalizations not in the wikipedia article, required to cover tests cases
// submitted by jehiah
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
// Convenience set of safe normalizations
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
// Convenience set of usually safe normalizations (includes FlagsSafe)
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
// Convenience set of all available flags
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
)
const (
defaultHttpPort = ":80"
defaultHttpsPort = ":443"
)
// Regular expressions used by the normalizations
var rxPort = regexp.MustCompile(`(:\d+)/?$`)
var rxDirIndex = regexp.MustCompile(`(^|/)((?:default|index)\.\w{1,4})$`)
var rxDupSlashes = regexp.MustCompile(`/{2,}`)
var rxDWORDHost = regexp.MustCompile(`^(\d+)((?:\.+)?(?:\:\d*)?)$`)
var rxOctalHost = regexp.MustCompile(`^(0\d*)\.(0\d*)\.(0\d*)\.(0\d*)((?:\.+)?(?:\:\d*)?)$`)
var rxHexHost = regexp.MustCompile(`^0x([0-9A-Fa-f]+)((?:\.+)?(?:\:\d*)?)$`)
var rxHostDots = regexp.MustCompile(`^(.+?)(:\d+)?$`)
var rxEmptyPort = regexp.MustCompile(`:+$`)
// Map of flags to implementation function.
// FlagDecodeUnnecessaryEscapes has no action, since it is done automatically
// by parsing the string as an URL. Same for FlagUppercaseEscapes and FlagRemoveEmptyQuerySeparator.
// Since maps have undefined traversing order, make a slice of ordered keys
var flagsOrder = []NormalizationFlags{
FlagLowercaseScheme,
FlagLowercaseHost,
FlagRemoveDefaultPort,
FlagRemoveDirectoryIndex,
FlagRemoveDotSegments,
FlagRemoveFragment,
FlagForceHTTP, // Must be after remove default port (because https=443/http=80)
FlagRemoveDuplicateSlashes,
FlagRemoveWWW,
FlagAddWWW,
FlagSortQuery,
FlagDecodeDWORDHost,
FlagDecodeOctalHost,
FlagDecodeHexHost,
FlagRemoveUnnecessaryHostDots,
FlagRemoveEmptyPortSeparator,
FlagRemoveTrailingSlash, // These two (add/remove trailing slash) must be last
FlagAddTrailingSlash,
}
// ... and then the map, where order is unimportant
var flags = map[NormalizationFlags]func(*url.URL){
FlagLowercaseScheme: lowercaseScheme,
FlagLowercaseHost: lowercaseHost,
FlagRemoveDefaultPort: removeDefaultPort,
FlagRemoveDirectoryIndex: removeDirectoryIndex,
FlagRemoveDotSegments: removeDotSegments,
FlagRemoveFragment: removeFragment,
FlagForceHTTP: forceHTTP,
FlagRemoveDuplicateSlashes: removeDuplicateSlashes,
FlagRemoveWWW: removeWWW,
FlagAddWWW: addWWW,
FlagSortQuery: sortQuery,
FlagDecodeDWORDHost: decodeDWORDHost,
FlagDecodeOctalHost: decodeOctalHost,
FlagDecodeHexHost: decodeHexHost,
FlagRemoveUnnecessaryHostDots: removeUnncessaryHostDots,
FlagRemoveEmptyPortSeparator: removeEmptyPortSeparator,
FlagRemoveTrailingSlash: removeTrailingSlash,
FlagAddTrailingSlash: addTrailingSlash,
}
// MustNormalizeURLString returns the normalized string, and panics if an error occurs.
// It takes an URL string as input, as well as the normalization flags.
func MustNormalizeURLString(u string, f NormalizationFlags) string {
result, e := NormalizeURLString(u, f)
if e != nil {
panic(e)
}
return result
}
// NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object.
// It takes an URL string as input, as well as the normalization flags.
func NormalizeURLString(u string, f NormalizationFlags) (string, error) {
if parsed, e := url.Parse(u); e != nil {
return "", e
} else {
options := make([]precis.Option, 1, 3)
options[0] = precis.IgnoreCase
if f&FlagLowercaseHost == FlagLowercaseHost {
options = append(options, precis.FoldCase())
}
options = append(options, precis.Norm(norm.NFC))
profile := precis.NewFreeform(options...)
if parsed.Host, e = idna.ToASCII(profile.NewTransformer().String(parsed.Host)); e != nil {
return "", e
}
return NormalizeURL(parsed, f), nil
}
panic("Unreachable code.")
}
// NormalizeURL returns the normalized string.
// It takes a parsed URL object as input, as well as the normalization flags.
func NormalizeURL(u *url.URL, f NormalizationFlags) string {
for _, k := range flagsOrder {
if f&k == k {
flags[k](u)
}
}
return urlesc.Escape(u)
}
func lowercaseScheme(u *url.URL) {
if len(u.Scheme) > 0 {
u.Scheme = strings.ToLower(u.Scheme)
}
}
func lowercaseHost(u *url.URL) {
if len(u.Host) > 0 {
u.Host = strings.ToLower(u.Host)
}
}
func removeDefaultPort(u *url.URL) {
if len(u.Host) > 0 {
scheme := strings.ToLower(u.Scheme)
u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string {
if (scheme == "http" && val == defaultHttpPort) || (scheme == "https" && val == defaultHttpsPort) {
return ""
}
return val
})
}
}
func removeTrailingSlash(u *url.URL) {
if l := len(u.Path); l > 0 {
if strings.HasSuffix(u.Path, "/") {
u.Path = u.Path[:l-1]
}
} else if l = len(u.Host); l > 0 {
if strings.HasSuffix(u.Host, "/") {
u.Host = u.Host[:l-1]
}
}
}
func addTrailingSlash(u *url.URL) {
if l := len(u.Path); l > 0 {
if !strings.HasSuffix(u.Path, "/") {
u.Path += "/"
}
} else if l = len(u.Host); l > 0 {
if !strings.HasSuffix(u.Host, "/") {
u.Host += "/"
}
}
}
func removeDotSegments(u *url.URL) {
if len(u.Path) > 0 {
var dotFree []string
var lastIsDot bool
sections := strings.Split(u.Path, "/")
for _, s := range sections {
if s == ".." {
if len(dotFree) > 0 {
dotFree = dotFree[:len(dotFree)-1]
}
} else if s != "." {
dotFree = append(dotFree, s)
}
lastIsDot = (s == "." || s == "..")
}
// Special case if host does not end with / and new path does not begin with /
u.Path = strings.Join(dotFree, "/")
if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") {
u.Path = "/" + u.Path
}
// Special case if the last segment was a dot, make sure the path ends with a slash
if lastIsDot && !strings.HasSuffix(u.Path, "/") {
u.Path += "/"
}
}
}
func removeDirectoryIndex(u *url.URL) {
if len(u.Path) > 0 {
u.Path = rxDirIndex.ReplaceAllString(u.Path, "$1")
}
}
func removeFragment(u *url.URL) {
u.Fragment = ""
}
func forceHTTP(u *url.URL) {
if strings.ToLower(u.Scheme) == "https" {
u.Scheme = "http"
}
}
func removeDuplicateSlashes(u *url.URL) {
if len(u.Path) > 0 {
u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/")
}
}
func removeWWW(u *url.URL) {
if len(u.Host) > 0 && strings.HasPrefix(strings.ToLower(u.Host), "www.") {
u.Host = u.Host[4:]
}
}
func addWWW(u *url.URL) {
if len(u.Host) > 0 && !strings.HasPrefix(strings.ToLower(u.Host), "www.") {
u.Host = "www." + u.Host
}
}
func sortQuery(u *url.URL) {
q := u.Query()
if len(q) > 0 {
arKeys := make([]string, len(q))
i := 0
for k, _ := range q {
arKeys[i] = k
i++
}
sort.Strings(arKeys)
buf := new(bytes.Buffer)
for _, k := range arKeys {
sort.Strings(q[k])
for _, v := range q[k] {
if buf.Len() > 0 {
buf.WriteRune('&')
}
buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v)))
}
}
// Rebuild the raw query string
u.RawQuery = buf.String()
}
}
func decodeDWORDHost(u *url.URL) {
if len(u.Host) > 0 {
if matches := rxDWORDHost.FindStringSubmatch(u.Host); len(matches) > 2 {
var parts [4]int64
dword, _ := strconv.ParseInt(matches[1], 10, 0)
for i, shift := range []uint{24, 16, 8, 0} {
parts[i] = dword >> shift & 0xFF
}
u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[2])
}
}
}
func decodeOctalHost(u *url.URL) {
if len(u.Host) > 0 {
if matches := rxOctalHost.FindStringSubmatch(u.Host); len(matches) > 5 {
var parts [4]int64
for i := 1; i <= 4; i++ {
parts[i-1], _ = strconv.ParseInt(matches[i], 8, 0)
}
u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[5])
}
}
}
func decodeHexHost(u *url.URL) {
if len(u.Host) > 0 {
if matches := rxHexHost.FindStringSubmatch(u.Host); len(matches) > 2 {
// Conversion is safe because of regex validation
parsed, _ := strconv.ParseInt(matches[1], 16, 0)
// Set host as DWORD (base 10) encoded host
u.Host = fmt.Sprintf("%d%s", parsed, matches[2])
// The rest is the same as decoding a DWORD host
decodeDWORDHost(u)
}
}
}
func removeUnncessaryHostDots(u *url.URL) {
if len(u.Host) > 0 {
if matches := rxHostDots.FindStringSubmatch(u.Host); len(matches) > 1 {
// Trim the leading and trailing dots
u.Host = strings.Trim(matches[1], ".")
if len(matches) > 2 {
u.Host += matches[2]
}
}
}
}
func removeEmptyPortSeparator(u *url.URL) {
if len(u.Host) > 0 {
u.Host = rxEmptyPort.ReplaceAllString(u.Host, "")
}
}

View File

@@ -1,768 +0,0 @@
package purell
import (
"fmt"
"net/url"
"testing"
)
type testCase struct {
nm string
src string
flgs NormalizationFlags
res string
parsed bool
}
var (
cases = [...]*testCase{
&testCase{
"LowerScheme",
"HTTP://www.SRC.ca",
FlagLowercaseScheme,
"http://www.SRC.ca",
false,
},
&testCase{
"LowerScheme2",
"http://www.SRC.ca",
FlagLowercaseScheme,
"http://www.SRC.ca",
false,
},
&testCase{
"LowerHost",
"HTTP://www.SRC.ca/",
FlagLowercaseHost,
"http://www.src.ca/", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"UpperEscapes",
`http://www.whatever.com/Some%aa%20Special%8Ecases/`,
FlagUppercaseEscapes,
"http://www.whatever.com/Some%AA%20Special%8Ecases/",
false,
},
&testCase{
"UnnecessaryEscapes",
`http://www.toto.com/%41%42%2E%44/%32%33%52%2D/%5f%7E`,
FlagDecodeUnnecessaryEscapes,
"http://www.toto.com/AB.D/23R-/_~",
false,
},
&testCase{
"RemoveDefaultPort",
"HTTP://www.SRC.ca:80/",
FlagRemoveDefaultPort,
"http://www.SRC.ca/", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveDefaultPort2",
"HTTP://www.SRC.ca:80",
FlagRemoveDefaultPort,
"http://www.SRC.ca", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveDefaultPort3",
"HTTP://www.SRC.ca:8080",
FlagRemoveDefaultPort,
"http://www.SRC.ca:8080", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"Safe",
"HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e",
FlagsSafe,
"http://www.src.ca/to%1Ato%8B%EE/OKnowABC~",
false,
},
&testCase{
"BothLower",
"HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e",
FlagLowercaseHost | FlagLowercaseScheme,
"http://www.src.ca:80/to%1Ato%8B%EE/OKnowABC~",
false,
},
&testCase{
"RemoveTrailingSlash",
"HTTP://www.SRC.ca:80/",
FlagRemoveTrailingSlash,
"http://www.SRC.ca:80", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveTrailingSlash2",
"HTTP://www.SRC.ca:80/toto/titi/",
FlagRemoveTrailingSlash,
"http://www.SRC.ca:80/toto/titi", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveTrailingSlash3",
"HTTP://www.SRC.ca:80/toto/titi/fin/?a=1",
FlagRemoveTrailingSlash,
"http://www.SRC.ca:80/toto/titi/fin?a=1", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"AddTrailingSlash",
"HTTP://www.SRC.ca:80",
FlagAddTrailingSlash,
"http://www.SRC.ca:80/", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"AddTrailingSlash2",
"HTTP://www.SRC.ca:80/toto/titi.html",
FlagAddTrailingSlash,
"http://www.SRC.ca:80/toto/titi.html/", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"AddTrailingSlash3",
"HTTP://www.SRC.ca:80/toto/titi/fin?a=1",
FlagAddTrailingSlash,
"http://www.SRC.ca:80/toto/titi/fin/?a=1", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveDotSegments",
"HTTP://root/a/b/./../../c/",
FlagRemoveDotSegments,
"http://root/c/", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveDotSegments2",
"HTTP://root/../a/b/./../c/../d",
FlagRemoveDotSegments,
"http://root/a/d", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"UsuallySafe",
"HTTP://www.SRC.ca:80/to%1ato%8b%ee/./c/d/../OKnow%41%42%43%7e/?a=b#test",
FlagsUsuallySafeGreedy,
"http://www.src.ca/to%1Ato%8B%EE/c/OKnowABC~?a=b#test",
false,
},
&testCase{
"RemoveDirectoryIndex",
"HTTP://root/a/b/c/default.aspx",
FlagRemoveDirectoryIndex,
"http://root/a/b/c/", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveDirectoryIndex2",
"HTTP://root/a/b/c/default#a=b",
FlagRemoveDirectoryIndex,
"http://root/a/b/c/default#a=b", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"RemoveFragment",
"HTTP://root/a/b/c/default#toto=tata",
FlagRemoveFragment,
"http://root/a/b/c/default", // Since Go1.1, scheme is automatically lowercased
false,
},
&testCase{
"ForceHTTP",
"https://root/a/b/c/default#toto=tata",
FlagForceHTTP,
"http://root/a/b/c/default#toto=tata",
false,
},
&testCase{
"RemoveDuplicateSlashes",
"https://root/a//b///c////default#toto=tata",
FlagRemoveDuplicateSlashes,
"https://root/a/b/c/default#toto=tata",
false,
},
&testCase{
"RemoveDuplicateSlashes2",
"https://root//a//b///c////default#toto=tata",
FlagRemoveDuplicateSlashes,
"https://root/a/b/c/default#toto=tata",
false,
},
&testCase{
"RemoveWWW",
"https://www.root/a/b/c/",
FlagRemoveWWW,
"https://root/a/b/c/",
false,
},
&testCase{
"RemoveWWW2",
"https://WwW.Root/a/b/c/",
FlagRemoveWWW,
"https://Root/a/b/c/",
false,
},
&testCase{
"AddWWW",
"https://Root/a/b/c/",
FlagAddWWW,
"https://www.Root/a/b/c/",
false,
},
&testCase{
"SortQuery",
"http://root/toto/?b=4&a=1&c=3&b=2&a=5",
FlagSortQuery,
"http://root/toto/?a=1&a=5&b=2&b=4&c=3",
false,
},
&testCase{
"RemoveEmptyQuerySeparator",
"http://root/toto/?",
FlagRemoveEmptyQuerySeparator,
"http://root/toto/",
false,
},
&testCase{
"Unsafe",
"HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
FlagsUnsafeGreedy,
"http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3",
false,
},
&testCase{
"Safe2",
"HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
FlagsSafe,
"https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
false,
},
&testCase{
"UsuallySafe2",
"HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
FlagsUsuallySafeGreedy,
"https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid",
false,
},
&testCase{
"AddTrailingSlashBug",
"http://src.ca/",
FlagsAllNonGreedy,
"http://www.src.ca/",
false,
},
&testCase{
"SourceModified",
"HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
FlagsUnsafeGreedy,
"http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3",
true,
},
&testCase{
"IPv6-1",
"http://[2001:db8:1f70::999:de8:7648:6e8]/test",
FlagsSafe | FlagRemoveDotSegments,
"http://[2001:db8:1f70::999:de8:7648:6e8]/test",
false,
},
&testCase{
"IPv6-2",
"http://[::ffff:192.168.1.1]/test",
FlagsSafe | FlagRemoveDotSegments,
"http://[::ffff:192.168.1.1]/test",
false,
},
&testCase{
"IPv6-3",
"http://[::ffff:192.168.1.1]:80/test",
FlagsSafe | FlagRemoveDotSegments,
"http://[::ffff:192.168.1.1]/test",
false,
},
&testCase{
"IPv6-4",
"htTps://[::fFff:192.168.1.1]:443/test",
FlagsSafe | FlagRemoveDotSegments,
"https://[::ffff:192.168.1.1]/test",
false,
},
&testCase{
"FTP",
"ftp://user:pass@ftp.foo.net/foo/bar",
FlagsSafe | FlagRemoveDotSegments,
"ftp://user:pass@ftp.foo.net/foo/bar",
false,
},
&testCase{
"Standard-1",
"http://www.foo.com:80/foo",
FlagsSafe | FlagRemoveDotSegments,
"http://www.foo.com/foo",
false,
},
&testCase{
"Standard-2",
"http://www.foo.com:8000/foo",
FlagsSafe | FlagRemoveDotSegments,
"http://www.foo.com:8000/foo",
false,
},
&testCase{
"Standard-3",
"http://www.foo.com/%7ebar",
FlagsSafe | FlagRemoveDotSegments,
"http://www.foo.com/~bar",
false,
},
&testCase{
"Standard-4",
"http://www.foo.com/%7Ebar",
FlagsSafe | FlagRemoveDotSegments,
"http://www.foo.com/~bar",
false,
},
&testCase{
"Standard-5",
"http://USER:pass@www.Example.COM/foo/bar",
FlagsSafe | FlagRemoveDotSegments,
"http://USER:pass@www.example.com/foo/bar",
false,
},
&testCase{
"Standard-6",
"http://test.example/?a=%26&b=1",
FlagsSafe | FlagRemoveDotSegments,
"http://test.example/?a=%26&b=1",
false,
},
&testCase{
"Standard-7",
"http://test.example/%25/?p=%20val%20%25",
FlagsSafe | FlagRemoveDotSegments,
"http://test.example/%25/?p=%20val%20%25",
false,
},
&testCase{
"Standard-8",
"http://test.example/path/with a%20space+/",
FlagsSafe | FlagRemoveDotSegments,
"http://test.example/path/with%20a%20space+/",
false,
},
&testCase{
"Standard-9",
"http://test.example/?",
FlagsSafe | FlagRemoveDotSegments,
"http://test.example/",
false,
},
&testCase{
"Standard-10",
"http://a.COM/path/?b&a",
FlagsSafe | FlagRemoveDotSegments,
"http://a.com/path/?b&a",
false,
},
&testCase{
"StandardCasesAddTrailingSlash",
"http://test.example?",
FlagsSafe | FlagAddTrailingSlash,
"http://test.example/",
false,
},
&testCase{
"OctalIP-1",
"http://0123.011.0.4/",
FlagsSafe | FlagDecodeOctalHost,
"http://0123.011.0.4/",
false,
},
&testCase{
"OctalIP-2",
"http://0102.0146.07.0223/",
FlagsSafe | FlagDecodeOctalHost,
"http://66.102.7.147/",
false,
},
&testCase{
"OctalIP-3",
"http://0102.0146.07.0223.:23/",
FlagsSafe | FlagDecodeOctalHost,
"http://66.102.7.147.:23/",
false,
},
&testCase{
"OctalIP-4",
"http://USER:pass@0102.0146.07.0223../",
FlagsSafe | FlagDecodeOctalHost,
"http://USER:pass@66.102.7.147../",
false,
},
&testCase{
"DWORDIP-1",
"http://123.1113982867/",
FlagsSafe | FlagDecodeDWORDHost,
"http://123.1113982867/",
false,
},
&testCase{
"DWORDIP-2",
"http://1113982867/",
FlagsSafe | FlagDecodeDWORDHost,
"http://66.102.7.147/",
false,
},
&testCase{
"DWORDIP-3",
"http://1113982867.:23/",
FlagsSafe | FlagDecodeDWORDHost,
"http://66.102.7.147.:23/",
false,
},
&testCase{
"DWORDIP-4",
"http://USER:pass@1113982867../",
FlagsSafe | FlagDecodeDWORDHost,
"http://USER:pass@66.102.7.147../",
false,
},
&testCase{
"HexIP-1",
"http://0x123.1113982867/",
FlagsSafe | FlagDecodeHexHost,
"http://0x123.1113982867/",
false,
},
&testCase{
"HexIP-2",
"http://0x42660793/",
FlagsSafe | FlagDecodeHexHost,
"http://66.102.7.147/",
false,
},
&testCase{
"HexIP-3",
"http://0x42660793.:23/",
FlagsSafe | FlagDecodeHexHost,
"http://66.102.7.147.:23/",
false,
},
&testCase{
"HexIP-4",
"http://USER:pass@0x42660793../",
FlagsSafe | FlagDecodeHexHost,
"http://USER:pass@66.102.7.147../",
false,
},
&testCase{
"UnnecessaryHostDots-1",
"http://.www.foo.com../foo/bar.html",
FlagsSafe | FlagRemoveUnnecessaryHostDots,
"http://www.foo.com/foo/bar.html",
false,
},
&testCase{
"UnnecessaryHostDots-2",
"http://www.foo.com./foo/bar.html",
FlagsSafe | FlagRemoveUnnecessaryHostDots,
"http://www.foo.com/foo/bar.html",
false,
},
&testCase{
"UnnecessaryHostDots-3",
"http://www.foo.com.:81/foo",
FlagsSafe | FlagRemoveUnnecessaryHostDots,
"http://www.foo.com:81/foo",
false,
},
&testCase{
"UnnecessaryHostDots-4",
"http://www.example.com./",
FlagsSafe | FlagRemoveUnnecessaryHostDots,
"http://www.example.com/",
false,
},
&testCase{
"EmptyPort-1",
"http://www.thedraymin.co.uk:/main/?p=308",
FlagsSafe | FlagRemoveEmptyPortSeparator,
"http://www.thedraymin.co.uk/main/?p=308",
false,
},
&testCase{
"EmptyPort-2",
"http://www.src.ca:",
FlagsSafe | FlagRemoveEmptyPortSeparator,
"http://www.src.ca",
false,
},
&testCase{
"Slashes-1",
"http://test.example/foo/bar/.",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/bar/",
false,
},
&testCase{
"Slashes-2",
"http://test.example/foo/bar/./",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/bar/",
false,
},
&testCase{
"Slashes-3",
"http://test.example/foo/bar/..",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/",
false,
},
&testCase{
"Slashes-4",
"http://test.example/foo/bar/../",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/",
false,
},
&testCase{
"Slashes-5",
"http://test.example/foo/bar/../baz",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/baz",
false,
},
&testCase{
"Slashes-6",
"http://test.example/foo/bar/../..",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/",
false,
},
&testCase{
"Slashes-7",
"http://test.example/foo/bar/../../",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/",
false,
},
&testCase{
"Slashes-8",
"http://test.example/foo/bar/../../baz",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/baz",
false,
},
&testCase{
"Slashes-9",
"http://test.example/foo/bar/../../../baz",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/baz",
false,
},
&testCase{
"Slashes-10",
"http://test.example/foo/bar/../../../../baz",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/baz",
false,
},
&testCase{
"Slashes-11",
"http://test.example/./foo",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo",
false,
},
&testCase{
"Slashes-12",
"http://test.example/../foo",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo",
false,
},
&testCase{
"Slashes-13",
"http://test.example/foo.",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo.",
false,
},
&testCase{
"Slashes-14",
"http://test.example/.foo",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/.foo",
false,
},
&testCase{
"Slashes-15",
"http://test.example/foo..",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo..",
false,
},
&testCase{
"Slashes-16",
"http://test.example/..foo",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/..foo",
false,
},
&testCase{
"Slashes-17",
"http://test.example/./../foo",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo",
false,
},
&testCase{
"Slashes-18",
"http://test.example/./foo/.",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/",
false,
},
&testCase{
"Slashes-19",
"http://test.example/foo/./bar",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/bar",
false,
},
&testCase{
"Slashes-20",
"http://test.example/foo/../bar",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/bar",
false,
},
&testCase{
"Slashes-21",
"http://test.example/foo//",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/",
false,
},
&testCase{
"Slashes-22",
"http://test.example/foo///bar//",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"http://test.example/foo/bar/",
false,
},
&testCase{
"Relative",
"foo/bar",
FlagsAllGreedy,
"foo/bar",
false,
},
&testCase{
"Relative-1",
"./../foo",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"foo",
false,
},
&testCase{
"Relative-2",
"./foo/bar/../baz/../bang/..",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"foo/",
false,
},
&testCase{
"Relative-3",
"foo///bar//",
FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
"foo/bar/",
false,
},
&testCase{
"Relative-4",
"www.youtube.com",
FlagsUsuallySafeGreedy,
"www.youtube.com",
false,
},
/*&testCase{
"UrlNorm-5",
"http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3",
FlagsSafe | FlagRemoveDotSegments,
"http://ja.wikipedia.org/wiki/\xe3\x82\xad\xe3\x83\xa3\xe3\x82\xbf\xe3\x83\x94\xe3\x83\xa9\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\x91\xe3\x83\xb3",
false,
},
&testCase{
"UrlNorm-1",
"http://test.example/?a=%e3%82%82%26",
FlagsAllGreedy,
"http://test.example/?a=\xe3\x82\x82%26",
false,
},*/
}
)
func TestRunner(t *testing.T) {
for _, tc := range cases {
runCase(tc, t)
}
}
func runCase(tc *testCase, t *testing.T) {
t.Logf("running %s...", tc.nm)
if tc.parsed {
u, e := url.Parse(tc.src)
if e != nil {
t.Errorf("%s - FAIL : %s", tc.nm, e)
return
} else {
NormalizeURL(u, tc.flgs)
if s := u.String(); s != tc.res {
t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s)
}
}
} else {
if s, e := NormalizeURLString(tc.src, tc.flgs); e != nil {
t.Errorf("%s - FAIL : %s", tc.nm, e)
} else if s != tc.res {
t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s)
}
}
}
func TestDecodeUnnecessaryEscapesAll(t *testing.T) {
var url = "http://host/"
for i := 0; i < 256; i++ {
url += fmt.Sprintf("%%%02x", i)
}
if s, e := NormalizeURLString(url, FlagDecodeUnnecessaryEscapes); e != nil {
t.Fatalf("Got error %s", e.Error())
} else {
const want = "http://host/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22%23$%25&'()*+,-./0123456789:;%3C=%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
if s != want {
t.Errorf("DecodeUnnecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s)
}
}
}
func TestEncodeNecessaryEscapesAll(t *testing.T) {
var url = "http://host/"
for i := 0; i < 256; i++ {
if i != 0x25 {
url += string(i)
}
}
if s, e := NormalizeURLString(url, FlagEncodeNecessaryEscapes); e != nil {
t.Fatalf("Got error %s", e.Error())
} else {
const want = "http://host/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22#$&'()*+,-./0123456789:;%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%C2%80%C2%81%C2%82%C2%83%C2%84%C2%85%C2%86%C2%87%C2%88%C2%89%C2%8A%C2%8B%C2%8C%C2%8D%C2%8E%C2%8F%C2%90%C2%91%C2%92%C2%93%C2%94%C2%95%C2%96%C2%97%C2%98%C2%99%C2%9A%C2%9B%C2%9C%C2%9D%C2%9E%C2%9F%C2%A0%C2%A1%C2%A2%C2%A3%C2%A4%C2%A5%C2%A6%C2%A7%C2%A8%C2%A9%C2%AA%C2%AB%C2%AC%C2%AD%C2%AE%C2%AF%C2%B0%C2%B1%C2%B2%C2%B3%C2%B4%C2%B5%C2%B6%C2%B7%C2%B8%C2%B9%C2%BA%C2%BB%C2%BC%C2%BD%C2%BE%C2%BF%C3%80%C3%81%C3%82%C3%83%C3%84%C3%85%C3%86%C3%87%C3%88%C3%89%C3%8A%C3%8B%C3%8C%C3%8D%C3%8E%C3%8F%C3%90%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%9B%C3%9C%C3%9D%C3%9E%C3%9F%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%A8%C3%A9%C3%AA%C3%AB%C3%AC%C3%AD%C3%AE%C3%AF%C3%B0%C3%B1%C3%B2%C3%B3%C3%B4%C3%B5%C3%B6%C3%B7%C3%B8%C3%B9%C3%BA%C3%BB%C3%BC%C3%BD%C3%BE%C3%BF"
if s != want {
t.Errorf("EncodeNecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s)
}
}
}

View File

@@ -1,52 +0,0 @@
package purell
import (
"testing"
)
// Test cases merged from PR #1
// Originally from https://github.com/jehiah/urlnorm/blob/master/test_urlnorm.py
func assertMap(t *testing.T, cases map[string]string, f NormalizationFlags) {
for bad, good := range cases {
s, e := NormalizeURLString(bad, f)
if e != nil {
t.Errorf("%s normalizing %v to %v", e.Error(), bad, good)
} else {
if s != good {
t.Errorf("source: %v expected: %v got: %v", bad, good, s)
}
}
}
}
// This tests normalization to a unicode representation
// precent escapes for unreserved values are unescaped to their unicode value
// tests normalization to idna domains
// test ip word handling, ipv6 address handling, and trailing domain periods
// in general, this matches google chromes unescaping for things in the address bar.
// spaces are converted to '+' (perhaphs controversial)
// http://code.google.com/p/google-url/ probably is another good reference for this approach
func TestUrlnorm(t *testing.T) {
testcases := map[string]string{
"http://test.example/?a=%e3%82%82%26": "http://test.example/?a=%e3%82%82%26",
//"http://test.example/?a=%e3%82%82%26": "http://test.example/?a=\xe3\x82\x82%26", //should return a unicode character
"http://s.xn--q-bga.DE/": "http://s.xn--q-bga.de/", //should be in idna format
"http://XBLA\u306eXbox.com": "http://xn--xblaxbox-jf4g.com", //test utf8 and unicode
"http://президент.рф": "http://xn--d1abbgf6aiiy.xn--p1ai",
"http://ПРЕЗИДЕНТ.РФ": "http://xn--d1abbgf6aiiy.xn--p1ai",
"http://\u00e9.com": "http://xn--9ca.com",
"http://e\u0301.com": "http://xn--9ca.com",
"http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3": "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3",
//"http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3": "http://ja.wikipedia.org/wiki/\xe3\x82\xad\xe3\x83\xa3\xe3\x82\xbf\xe3\x83\x94\xe3\x83\xa9\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\x91\xe3\x83\xb3",
"http://test.example/\xe3\x82\xad": "http://test.example/%E3%82%AD",
//"http://test.example/\xe3\x82\xad": "http://test.example/\xe3\x82\xad",
"http://test.example/?p=%23val#test-%23-val%25": "http://test.example/?p=%23val#test-%23-val%25", //check that %23 (#) is not escaped where it shouldn't be
"http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n": "http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n",
//"http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n": "http://test.domain/I\xc3\xb1t\xc3\xabrn\xc3\xa2ti\xc3\xb4n\xef\xbf\xbdliz\xc3\xa6ti\xc3\xb8n",
}
assertMap(t, testcases, FlagsSafe|FlagRemoveDotSegments)
}

View File

@@ -1,11 +0,0 @@
language: go
go:
- 1.4
- tip
install:
- go build .
script:
- go test -v

View File

@@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,16 +0,0 @@
urlesc [![Build Status](https://travis-ci.org/PuerkitoBio/urlesc.png?branch=master)](https://travis-ci.org/PuerkitoBio/urlesc) [![GoDoc](http://godoc.org/github.com/PuerkitoBio/urlesc?status.svg)](http://godoc.org/github.com/PuerkitoBio/urlesc)
======
Package urlesc implements query escaping as per RFC 3986.
It contains some parts of the net/url package, modified so as to allow
some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)).
## Install
go get github.com/PuerkitoBio/urlesc
## License
Go license (BSD-3-Clause)

View File

@@ -1,180 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package urlesc implements query escaping as per RFC 3986.
// It contains some parts of the net/url package, modified so as to allow
// some reserved characters incorrectly escaped by net/url.
// See https://github.com/golang/go/issues/5684
package urlesc
import (
"bytes"
"net/url"
"strings"
)
type encoding int
const (
encodePath encoding = 1 + iota
encodeUserPassword
encodeQueryComponent
encodeFragment
)
// Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 3986.
func shouldEscape(c byte, mode encoding) bool {
// §2.3 Unreserved characters (alphanum)
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
return false
}
switch c {
case '-', '.', '_', '~': // §2.3 Unreserved characters (mark)
return false
// §2.2 Reserved characters (reserved)
case ':', '/', '?', '#', '[', ']', '@', // gen-delims
'!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims
// Different sections of the URL allow a few of
// the reserved characters to appear unescaped.
switch mode {
case encodePath: // §3.3
// The RFC allows sub-delims and : @.
// '/', '[' and ']' can be used to assign meaning to individual path
// segments. This package only manipulates the path as a whole,
// so we allow those as well. That leaves only ? and # to escape.
return c == '?' || c == '#'
case encodeUserPassword: // §3.2.1
// The RFC allows : and sub-delims in
// userinfo. The parsing of userinfo treats ':' as special so we must escape
// all the gen-delims.
return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
case encodeQueryComponent: // §3.4
// The RFC allows / and ?.
return c != '/' && c != '?'
case encodeFragment: // §4.1
// The RFC text is silent but the grammar allows
// everything, so escape nothing but #
return c == '#'
}
}
// Everything else must be escaped.
return true
}
// QueryEscape escapes the string so it can be safely placed
// inside a URL query.
func QueryEscape(s string) string {
return escape(s, encodeQueryComponent)
}
func escape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
c := s[i]
if shouldEscape(c, mode) {
if c == ' ' && mode == encodeQueryComponent {
spaceCount++
} else {
hexCount++
}
}
}
if spaceCount == 0 && hexCount == 0 {
return s
}
t := make([]byte, len(s)+2*hexCount)
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
case c == ' ' && mode == encodeQueryComponent:
t[j] = '+'
j++
case shouldEscape(c, mode):
t[j] = '%'
t[j+1] = "0123456789ABCDEF"[c>>4]
t[j+2] = "0123456789ABCDEF"[c&15]
j += 3
default:
t[j] = s[i]
j++
}
}
return string(t)
}
var uiReplacer = strings.NewReplacer(
"%21", "!",
"%27", "'",
"%28", "(",
"%29", ")",
"%2A", "*",
)
// unescapeUserinfo unescapes some characters that need not to be escaped as per RFC3986.
func unescapeUserinfo(s string) string {
return uiReplacer.Replace(s)
}
// Escape reassembles the URL into a valid URL string.
// The general form of the result is one of:
//
// scheme:opaque
// scheme://userinfo@host/path?query#fragment
//
// If u.Opaque is non-empty, String uses the first form;
// otherwise it uses the second form.
//
// In the second form, the following rules apply:
// - if u.Scheme is empty, scheme: is omitted.
// - if u.User is nil, userinfo@ is omitted.
// - if u.Host is empty, host/ is omitted.
// - if u.Scheme and u.Host are empty and u.User is nil,
// the entire scheme://userinfo@host/ is omitted.
// - if u.Host is non-empty and u.Path begins with a /,
// the form host/path does not add its own /.
// - if u.RawQuery is empty, ?query is omitted.
// - if u.Fragment is empty, #fragment is omitted.
func Escape(u *url.URL) string {
var buf bytes.Buffer
if u.Scheme != "" {
buf.WriteString(u.Scheme)
buf.WriteByte(':')
}
if u.Opaque != "" {
buf.WriteString(u.Opaque)
} else {
if u.Scheme != "" || u.Host != "" || u.User != nil {
buf.WriteString("//")
if ui := u.User; ui != nil {
buf.WriteString(unescapeUserinfo(ui.String()))
buf.WriteByte('@')
}
if h := u.Host; h != "" {
buf.WriteString(h)
}
}
if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
buf.WriteByte('/')
}
buf.WriteString(escape(u.Path, encodePath))
}
if u.RawQuery != "" {
buf.WriteByte('?')
buf.WriteString(u.RawQuery)
}
if u.Fragment != "" {
buf.WriteByte('#')
buf.WriteString(escape(u.Fragment, encodeFragment))
}
return buf.String()
}

View File

@@ -1,641 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package urlesc
import (
"net/url"
"testing"
)
type URLTest struct {
in string
out *url.URL
roundtrip string // expected result of reserializing the URL; empty means same as "in".
}
var urltests = []URLTest{
// no path
{
"http://www.google.com",
&url.URL{
Scheme: "http",
Host: "www.google.com",
},
"",
},
// path
{
"http://www.google.com/",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/",
},
"",
},
// path with hex escaping
{
"http://www.google.com/file%20one%26two",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/file one&two",
},
"http://www.google.com/file%20one&two",
},
// user
{
"ftp://webmaster@www.google.com/",
&url.URL{
Scheme: "ftp",
User: url.User("webmaster"),
Host: "www.google.com",
Path: "/",
},
"",
},
// escape sequence in username
{
"ftp://john%20doe@www.google.com/",
&url.URL{
Scheme: "ftp",
User: url.User("john doe"),
Host: "www.google.com",
Path: "/",
},
"ftp://john%20doe@www.google.com/",
},
// query
{
"http://www.google.com/?q=go+language",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/",
RawQuery: "q=go+language",
},
"",
},
// query with hex escaping: NOT parsed
{
"http://www.google.com/?q=go%20language",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/",
RawQuery: "q=go%20language",
},
"",
},
// %20 outside query
{
"http://www.google.com/a%20b?q=c+d",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/a b",
RawQuery: "q=c+d",
},
"",
},
// path without leading /, so no parsing
{
"http:www.google.com/?q=go+language",
&url.URL{
Scheme: "http",
Opaque: "www.google.com/",
RawQuery: "q=go+language",
},
"http:www.google.com/?q=go+language",
},
// path without leading /, so no parsing
{
"http:%2f%2fwww.google.com/?q=go+language",
&url.URL{
Scheme: "http",
Opaque: "%2f%2fwww.google.com/",
RawQuery: "q=go+language",
},
"http:%2f%2fwww.google.com/?q=go+language",
},
// non-authority with path
{
"mailto:/webmaster@golang.org",
&url.URL{
Scheme: "mailto",
Path: "/webmaster@golang.org",
},
"mailto:///webmaster@golang.org", // unfortunate compromise
},
// non-authority
{
"mailto:webmaster@golang.org",
&url.URL{
Scheme: "mailto",
Opaque: "webmaster@golang.org",
},
"",
},
// unescaped :// in query should not create a scheme
{
"/foo?query=http://bad",
&url.URL{
Path: "/foo",
RawQuery: "query=http://bad",
},
"",
},
// leading // without scheme should create an authority
{
"//foo",
&url.URL{
Host: "foo",
},
"",
},
// leading // without scheme, with userinfo, path, and query
{
"//user@foo/path?a=b",
&url.URL{
User: url.User("user"),
Host: "foo",
Path: "/path",
RawQuery: "a=b",
},
"",
},
// Three leading slashes isn't an authority, but doesn't return an error.
// (We can't return an error, as this code is also used via
// ServeHTTP -> ReadRequest -> Parse, which is arguably a
// different URL parsing context, but currently shares the
// same codepath)
{
"///threeslashes",
&url.URL{
Path: "///threeslashes",
},
"",
},
{
"http://user:password@google.com",
&url.URL{
Scheme: "http",
User: url.UserPassword("user", "password"),
Host: "google.com",
},
"http://user:password@google.com",
},
// unescaped @ in username should not confuse host
{
"http://j@ne:password@google.com",
&url.URL{
Scheme: "http",
User: url.UserPassword("j@ne", "password"),
Host: "google.com",
},
"http://j%40ne:password@google.com",
},
// unescaped @ in password should not confuse host
{
"http://jane:p@ssword@google.com",
&url.URL{
Scheme: "http",
User: url.UserPassword("jane", "p@ssword"),
Host: "google.com",
},
"http://jane:p%40ssword@google.com",
},
{
"http://j@ne:password@google.com/p@th?q=@go",
&url.URL{
Scheme: "http",
User: url.UserPassword("j@ne", "password"),
Host: "google.com",
Path: "/p@th",
RawQuery: "q=@go",
},
"http://j%40ne:password@google.com/p@th?q=@go",
},
{
"http://www.google.com/?q=go+language#foo",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/",
RawQuery: "q=go+language",
Fragment: "foo",
},
"",
},
{
"http://www.google.com/?q=go+language#foo%26bar",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/",
RawQuery: "q=go+language",
Fragment: "foo&bar",
},
"http://www.google.com/?q=go+language#foo&bar",
},
{
"file:///home/adg/rabbits",
&url.URL{
Scheme: "file",
Host: "",
Path: "/home/adg/rabbits",
},
"file:///home/adg/rabbits",
},
// "Windows" paths are no exception to the rule.
// See golang.org/issue/6027, especially comment #9.
{
"file:///C:/FooBar/Baz.txt",
&url.URL{
Scheme: "file",
Host: "",
Path: "/C:/FooBar/Baz.txt",
},
"file:///C:/FooBar/Baz.txt",
},
// case-insensitive scheme
{
"MaIlTo:webmaster@golang.org",
&url.URL{
Scheme: "mailto",
Opaque: "webmaster@golang.org",
},
"mailto:webmaster@golang.org",
},
// Relative path
{
"a/b/c",
&url.URL{
Path: "a/b/c",
},
"a/b/c",
},
// escaped '?' in username and password
{
"http://%3Fam:pa%3Fsword@google.com",
&url.URL{
Scheme: "http",
User: url.UserPassword("?am", "pa?sword"),
Host: "google.com",
},
"",
},
// escaped '?' and '#' in path
{
"http://example.com/%3F%23",
&url.URL{
Scheme: "http",
Host: "example.com",
Path: "?#",
},
"",
},
// unescaped [ ] ! ' ( ) * in path
{
"http://example.com/[]!'()*",
&url.URL{
Scheme: "http",
Host: "example.com",
Path: "[]!'()*",
},
"http://example.com/[]!'()*",
},
// escaped : / ? # [ ] @ in username and password
{
"http://%3A%2F%3F:%23%5B%5D%40@example.com",
&url.URL{
Scheme: "http",
User: url.UserPassword(":/?", "#[]@"),
Host: "example.com",
},
"",
},
// unescaped ! $ & ' ( ) * + , ; = in username and password
{
"http://!$&'():*+,;=@example.com",
&url.URL{
Scheme: "http",
User: url.UserPassword("!$&'()", "*+,;="),
Host: "example.com",
},
"",
},
// unescaped = : / . ? = in query component
{
"http://example.com/?q=http://google.com/?q=",
&url.URL{
Scheme: "http",
Host: "example.com",
Path: "/",
RawQuery: "q=http://google.com/?q=",
},
"",
},
// unescaped : / ? [ ] @ ! $ & ' ( ) * + , ; = in fragment
{
"http://example.com/#:/?%23[]@!$&'()*+,;=",
&url.URL{
Scheme: "http",
Host: "example.com",
Path: "/",
Fragment: ":/?#[]@!$&'()*+,;=",
},
"",
},
}
func DoTestString(t *testing.T, parse func(string) (*url.URL, error), name string, tests []URLTest) {
for _, tt := range tests {
u, err := parse(tt.in)
if err != nil {
t.Errorf("%s(%q) returned error %s", name, tt.in, err)
continue
}
expected := tt.in
if len(tt.roundtrip) > 0 {
expected = tt.roundtrip
}
s := Escape(u)
if s != expected {
t.Errorf("Escape(%s(%q)) == %q (expected %q)", name, tt.in, s, expected)
}
}
}
func TestURLString(t *testing.T) {
DoTestString(t, url.Parse, "Parse", urltests)
// no leading slash on path should prepend
// slash on String() call
noslash := URLTest{
"http://www.google.com/search",
&url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "search",
},
"",
}
s := Escape(noslash.out)
if s != noslash.in {
t.Errorf("Expected %s; go %s", noslash.in, s)
}
}
type EscapeTest struct {
in string
out string
err error
}
var escapeTests = []EscapeTest{
{
"",
"",
nil,
},
{
"abc",
"abc",
nil,
},
{
"one two",
"one+two",
nil,
},
{
"10%",
"10%25",
nil,
},
{
" ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;",
"+?%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A/%40%24%27%28%29%2A%2C%3B",
nil,
},
}
func TestEscape(t *testing.T) {
for _, tt := range escapeTests {
actual := QueryEscape(tt.in)
if tt.out != actual {
t.Errorf("QueryEscape(%q) = %q, want %q", tt.in, actual, tt.out)
}
// for bonus points, verify that escape:unescape is an identity.
roundtrip, err := url.QueryUnescape(actual)
if roundtrip != tt.in || err != nil {
t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
}
}
}
var resolveReferenceTests = []struct {
base, rel, expected string
}{
// Absolute URL references
{"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
{"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
{"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"},
// Path-absolute references
{"http://foo.com/bar", "/baz", "http://foo.com/baz"},
{"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
{"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
// Scheme-relative
{"https://foo.com/bar?a=b", "//bar.com/quux", "https://bar.com/quux"},
// Path-relative references:
// ... current directory
{"http://foo.com", ".", "http://foo.com/"},
{"http://foo.com/bar", ".", "http://foo.com/"},
{"http://foo.com/bar/", ".", "http://foo.com/bar/"},
// ... going down
{"http://foo.com", "bar", "http://foo.com/bar"},
{"http://foo.com/", "bar", "http://foo.com/bar"},
{"http://foo.com/bar/baz", "quux", "http://foo.com/bar/quux"},
// ... going up
{"http://foo.com/bar/baz", "../quux", "http://foo.com/quux"},
{"http://foo.com/bar/baz", "../../../../../quux", "http://foo.com/quux"},
{"http://foo.com/bar", "..", "http://foo.com/"},
{"http://foo.com/bar/baz", "./..", "http://foo.com/"},
// ".." in the middle (issue 3560)
{"http://foo.com/bar/baz", "quux/dotdot/../tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/../tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/.././tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/./../tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/dotdot/././../../tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/dotdot/./.././../tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/dotdot/dotdot/./../../.././././tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/../dotdot/../dot/./tail/..", "http://foo.com/bar/quux/dot/"},
// Remove any dot-segments prior to forming the target URI.
// http://tools.ietf.org/html/rfc3986#section-5.2.4
{"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/baz"},
// Triple dot isn't special
{"http://foo.com/bar", "...", "http://foo.com/..."},
// Fragment
{"http://foo.com/bar", ".#frag", "http://foo.com/#frag"},
// RFC 3986: Normal Examples
// http://tools.ietf.org/html/rfc3986#section-5.4.1
{"http://a/b/c/d;p?q", "g:h", "g:h"},
{"http://a/b/c/d;p?q", "g", "http://a/b/c/g"},
{"http://a/b/c/d;p?q", "./g", "http://a/b/c/g"},
{"http://a/b/c/d;p?q", "g/", "http://a/b/c/g/"},
{"http://a/b/c/d;p?q", "/g", "http://a/g"},
{"http://a/b/c/d;p?q", "//g", "http://g"},
{"http://a/b/c/d;p?q", "?y", "http://a/b/c/d;p?y"},
{"http://a/b/c/d;p?q", "g?y", "http://a/b/c/g?y"},
{"http://a/b/c/d;p?q", "#s", "http://a/b/c/d;p?q#s"},
{"http://a/b/c/d;p?q", "g#s", "http://a/b/c/g#s"},
{"http://a/b/c/d;p?q", "g?y#s", "http://a/b/c/g?y#s"},
{"http://a/b/c/d;p?q", ";x", "http://a/b/c/;x"},
{"http://a/b/c/d;p?q", "g;x", "http://a/b/c/g;x"},
{"http://a/b/c/d;p?q", "g;x?y#s", "http://a/b/c/g;x?y#s"},
{"http://a/b/c/d;p?q", "", "http://a/b/c/d;p?q"},
{"http://a/b/c/d;p?q", ".", "http://a/b/c/"},
{"http://a/b/c/d;p?q", "./", "http://a/b/c/"},
{"http://a/b/c/d;p?q", "..", "http://a/b/"},
{"http://a/b/c/d;p?q", "../", "http://a/b/"},
{"http://a/b/c/d;p?q", "../g", "http://a/b/g"},
{"http://a/b/c/d;p?q", "../..", "http://a/"},
{"http://a/b/c/d;p?q", "../../", "http://a/"},
{"http://a/b/c/d;p?q", "../../g", "http://a/g"},
// RFC 3986: Abnormal Examples
// http://tools.ietf.org/html/rfc3986#section-5.4.2
{"http://a/b/c/d;p?q", "../../../g", "http://a/g"},
{"http://a/b/c/d;p?q", "../../../../g", "http://a/g"},
{"http://a/b/c/d;p?q", "/./g", "http://a/g"},
{"http://a/b/c/d;p?q", "/../g", "http://a/g"},
{"http://a/b/c/d;p?q", "g.", "http://a/b/c/g."},
{"http://a/b/c/d;p?q", ".g", "http://a/b/c/.g"},
{"http://a/b/c/d;p?q", "g..", "http://a/b/c/g.."},
{"http://a/b/c/d;p?q", "..g", "http://a/b/c/..g"},
{"http://a/b/c/d;p?q", "./../g", "http://a/b/g"},
{"http://a/b/c/d;p?q", "./g/.", "http://a/b/c/g/"},
{"http://a/b/c/d;p?q", "g/./h", "http://a/b/c/g/h"},
{"http://a/b/c/d;p?q", "g/../h", "http://a/b/c/h"},
{"http://a/b/c/d;p?q", "g;x=1/./y", "http://a/b/c/g;x=1/y"},
{"http://a/b/c/d;p?q", "g;x=1/../y", "http://a/b/c/y"},
{"http://a/b/c/d;p?q", "g?y/./x", "http://a/b/c/g?y/./x"},
{"http://a/b/c/d;p?q", "g?y/../x", "http://a/b/c/g?y/../x"},
{"http://a/b/c/d;p?q", "g#s/./x", "http://a/b/c/g#s/./x"},
{"http://a/b/c/d;p?q", "g#s/../x", "http://a/b/c/g#s/../x"},
// Extras.
{"https://a/b/c/d;p?q", "//g?q", "https://g?q"},
{"https://a/b/c/d;p?q", "//g#s", "https://g#s"},
{"https://a/b/c/d;p?q", "//g/d/e/f?y#s", "https://g/d/e/f?y#s"},
{"https://a/b/c/d;p#s", "?y", "https://a/b/c/d;p?y"},
{"https://a/b/c/d;p?q#s", "?y", "https://a/b/c/d;p?y"},
}
func TestResolveReference(t *testing.T) {
mustParse := func(url_ string) *url.URL {
u, err := url.Parse(url_)
if err != nil {
t.Fatalf("Expected URL to parse: %q, got error: %v", url_, err)
}
return u
}
opaque := &url.URL{Scheme: "scheme", Opaque: "opaque"}
for _, test := range resolveReferenceTests {
base := mustParse(test.base)
rel := mustParse(test.rel)
url := base.ResolveReference(rel)
if Escape(url) != test.expected {
t.Errorf("URL(%q).ResolveReference(%q) == %q, got %q", test.base, test.rel, test.expected, Escape(url))
}
// Ensure that new instances are returned.
if base == url {
t.Errorf("Expected URL.ResolveReference to return new URL instance.")
}
// Test the convenience wrapper too.
url, err := base.Parse(test.rel)
if err != nil {
t.Errorf("URL(%q).Parse(%q) failed: %v", test.base, test.rel, err)
} else if Escape(url) != test.expected {
t.Errorf("URL(%q).Parse(%q) == %q, got %q", test.base, test.rel, test.expected, Escape(url))
} else if base == url {
// Ensure that new instances are returned for the wrapper too.
t.Errorf("Expected URL.Parse to return new URL instance.")
}
// Ensure Opaque resets the URL.
url = base.ResolveReference(opaque)
if *url != *opaque {
t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", url, opaque)
}
// Test the convenience wrapper with an opaque URL too.
url, err = base.Parse("scheme:opaque")
if err != nil {
t.Errorf(`URL(%q).Parse("scheme:opaque") failed: %v`, test.base, err)
} else if *url != *opaque {
t.Errorf("Parse failed to resolve opaque URL: want %#v, got %#v", url, opaque)
} else if base == url {
// Ensure that new instances are returned, again.
t.Errorf("Expected URL.Parse to return new URL instance.")
}
}
}
type shouldEscapeTest struct {
in byte
mode encoding
escape bool
}
var shouldEscapeTests = []shouldEscapeTest{
// Unreserved characters (§2.3)
{'a', encodePath, false},
{'a', encodeUserPassword, false},
{'a', encodeQueryComponent, false},
{'a', encodeFragment, false},
{'z', encodePath, false},
{'A', encodePath, false},
{'Z', encodePath, false},
{'0', encodePath, false},
{'9', encodePath, false},
{'-', encodePath, false},
{'-', encodeUserPassword, false},
{'-', encodeQueryComponent, false},
{'-', encodeFragment, false},
{'.', encodePath, false},
{'_', encodePath, false},
{'~', encodePath, false},
// User information (§3.2.1)
{':', encodeUserPassword, true},
{'/', encodeUserPassword, true},
{'?', encodeUserPassword, true},
{'@', encodeUserPassword, true},
{'$', encodeUserPassword, false},
{'&', encodeUserPassword, false},
{'+', encodeUserPassword, false},
{',', encodeUserPassword, false},
{';', encodeUserPassword, false},
{'=', encodeUserPassword, false},
}
func TestShouldEscape(t *testing.T) {
for _, tt := range shouldEscapeTests {
if shouldEscape(tt.in, tt.mode) != tt.escape {
t.Errorf("shouldEscape(%q, %v) returned %v; expected %v", tt.in, tt.mode, !tt.escape, tt.escape)
}
}
}

View File

@@ -1,22 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe

View File

@@ -1,14 +0,0 @@
language: go
go:
- 1.5.4
- 1.6.3
- 1.7
install:
- go get -v golang.org/x/tools/cmd/cover
script:
- go test -v -tags=safe ./spew
- go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
after_success:
- go get -v github.com/mattn/goveralls
- export PATH=$PATH:$HOME/gopath/bin
- goveralls -coverprofile=profile.cov -service=travis-ci

View File

@@ -1,15 +0,0 @@
ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Some files were not shown because too many files have changed in this diff Show More