1/* 2Copyright 2015 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package testing 18 19import ( 20 "fmt" 21 "path" 22 "strings" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/fields" 26 "k8s.io/apimachinery/pkg/labels" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/apimachinery/pkg/runtime/schema" 29 "k8s.io/apimachinery/pkg/types" 30) 31 32func NewRootGetAction(resource schema.GroupVersionResource, name string) GetActionImpl { 33 action := GetActionImpl{} 34 action.Verb = "get" 35 action.Resource = resource 36 action.Name = name 37 38 return action 39} 40 41func NewGetAction(resource schema.GroupVersionResource, namespace, name string) GetActionImpl { 42 action := GetActionImpl{} 43 action.Verb = "get" 44 action.Resource = resource 45 action.Namespace = namespace 46 action.Name = name 47 48 return action 49} 50 51func NewGetSubresourceAction(resource schema.GroupVersionResource, namespace, subresource, name string) GetActionImpl { 52 action := GetActionImpl{} 53 action.Verb = "get" 54 action.Resource = resource 55 action.Subresource = subresource 56 action.Namespace = namespace 57 action.Name = name 58 59 return action 60} 61 62func NewRootGetSubresourceAction(resource schema.GroupVersionResource, subresource, name string) GetActionImpl { 63 action := GetActionImpl{} 64 action.Verb = "get" 65 action.Resource = resource 66 action.Subresource = subresource 67 action.Name = name 68 69 return action 70} 71 72func NewRootListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, opts interface{}) ListActionImpl { 73 action := ListActionImpl{} 74 action.Verb = "list" 75 action.Resource = resource 76 action.Kind = kind 77 labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) 78 action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} 79 80 return action 81} 82 83func NewListAction(resource schema.GroupVersionResource, kind schema.GroupVersionKind, namespace string, opts interface{}) ListActionImpl { 84 action := ListActionImpl{} 85 action.Verb = "list" 86 action.Resource = resource 87 action.Kind = kind 88 action.Namespace = namespace 89 labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) 90 action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} 91 92 return action 93} 94 95func NewRootCreateAction(resource schema.GroupVersionResource, object runtime.Object) CreateActionImpl { 96 action := CreateActionImpl{} 97 action.Verb = "create" 98 action.Resource = resource 99 action.Object = object 100 101 return action 102} 103 104func NewCreateAction(resource schema.GroupVersionResource, namespace string, object runtime.Object) CreateActionImpl { 105 action := CreateActionImpl{} 106 action.Verb = "create" 107 action.Resource = resource 108 action.Namespace = namespace 109 action.Object = object 110 111 return action 112} 113 114func NewRootCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource string, object runtime.Object) CreateActionImpl { 115 action := CreateActionImpl{} 116 action.Verb = "create" 117 action.Resource = resource 118 action.Subresource = subresource 119 action.Name = name 120 action.Object = object 121 122 return action 123} 124 125func NewCreateSubresourceAction(resource schema.GroupVersionResource, name, subresource, namespace string, object runtime.Object) CreateActionImpl { 126 action := CreateActionImpl{} 127 action.Verb = "create" 128 action.Resource = resource 129 action.Namespace = namespace 130 action.Subresource = subresource 131 action.Name = name 132 action.Object = object 133 134 return action 135} 136 137func NewRootUpdateAction(resource schema.GroupVersionResource, object runtime.Object) UpdateActionImpl { 138 action := UpdateActionImpl{} 139 action.Verb = "update" 140 action.Resource = resource 141 action.Object = object 142 143 return action 144} 145 146func NewUpdateAction(resource schema.GroupVersionResource, namespace string, object runtime.Object) UpdateActionImpl { 147 action := UpdateActionImpl{} 148 action.Verb = "update" 149 action.Resource = resource 150 action.Namespace = namespace 151 action.Object = object 152 153 return action 154} 155 156func NewRootPatchAction(resource schema.GroupVersionResource, name string, pt types.PatchType, patch []byte) PatchActionImpl { 157 action := PatchActionImpl{} 158 action.Verb = "patch" 159 action.Resource = resource 160 action.Name = name 161 action.PatchType = pt 162 action.Patch = patch 163 164 return action 165} 166 167func NewPatchAction(resource schema.GroupVersionResource, namespace string, name string, pt types.PatchType, patch []byte) PatchActionImpl { 168 action := PatchActionImpl{} 169 action.Verb = "patch" 170 action.Resource = resource 171 action.Namespace = namespace 172 action.Name = name 173 action.PatchType = pt 174 action.Patch = patch 175 176 return action 177} 178 179func NewRootPatchSubresourceAction(resource schema.GroupVersionResource, name string, pt types.PatchType, patch []byte, subresources ...string) PatchActionImpl { 180 action := PatchActionImpl{} 181 action.Verb = "patch" 182 action.Resource = resource 183 action.Subresource = path.Join(subresources...) 184 action.Name = name 185 action.PatchType = pt 186 action.Patch = patch 187 188 return action 189} 190 191func NewPatchSubresourceAction(resource schema.GroupVersionResource, namespace, name string, pt types.PatchType, patch []byte, subresources ...string) PatchActionImpl { 192 action := PatchActionImpl{} 193 action.Verb = "patch" 194 action.Resource = resource 195 action.Subresource = path.Join(subresources...) 196 action.Namespace = namespace 197 action.Name = name 198 action.PatchType = pt 199 action.Patch = patch 200 201 return action 202} 203 204func NewRootUpdateSubresourceAction(resource schema.GroupVersionResource, subresource string, object runtime.Object) UpdateActionImpl { 205 action := UpdateActionImpl{} 206 action.Verb = "update" 207 action.Resource = resource 208 action.Subresource = subresource 209 action.Object = object 210 211 return action 212} 213func NewUpdateSubresourceAction(resource schema.GroupVersionResource, subresource string, namespace string, object runtime.Object) UpdateActionImpl { 214 action := UpdateActionImpl{} 215 action.Verb = "update" 216 action.Resource = resource 217 action.Subresource = subresource 218 action.Namespace = namespace 219 action.Object = object 220 221 return action 222} 223 224func NewRootDeleteAction(resource schema.GroupVersionResource, name string) DeleteActionImpl { 225 action := DeleteActionImpl{} 226 action.Verb = "delete" 227 action.Resource = resource 228 action.Name = name 229 230 return action 231} 232 233func NewRootDeleteSubresourceAction(resource schema.GroupVersionResource, subresource string, name string) DeleteActionImpl { 234 action := DeleteActionImpl{} 235 action.Verb = "delete" 236 action.Resource = resource 237 action.Subresource = subresource 238 action.Name = name 239 240 return action 241} 242 243func NewDeleteAction(resource schema.GroupVersionResource, namespace, name string) DeleteActionImpl { 244 action := DeleteActionImpl{} 245 action.Verb = "delete" 246 action.Resource = resource 247 action.Namespace = namespace 248 action.Name = name 249 250 return action 251} 252 253func NewDeleteSubresourceAction(resource schema.GroupVersionResource, subresource, namespace, name string) DeleteActionImpl { 254 action := DeleteActionImpl{} 255 action.Verb = "delete" 256 action.Resource = resource 257 action.Subresource = subresource 258 action.Namespace = namespace 259 action.Name = name 260 261 return action 262} 263 264func NewRootDeleteCollectionAction(resource schema.GroupVersionResource, opts interface{}) DeleteCollectionActionImpl { 265 action := DeleteCollectionActionImpl{} 266 action.Verb = "delete-collection" 267 action.Resource = resource 268 labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) 269 action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} 270 271 return action 272} 273 274func NewDeleteCollectionAction(resource schema.GroupVersionResource, namespace string, opts interface{}) DeleteCollectionActionImpl { 275 action := DeleteCollectionActionImpl{} 276 action.Verb = "delete-collection" 277 action.Resource = resource 278 action.Namespace = namespace 279 labelSelector, fieldSelector, _ := ExtractFromListOptions(opts) 280 action.ListRestrictions = ListRestrictions{labelSelector, fieldSelector} 281 282 return action 283} 284 285func NewRootWatchAction(resource schema.GroupVersionResource, opts interface{}) WatchActionImpl { 286 action := WatchActionImpl{} 287 action.Verb = "watch" 288 action.Resource = resource 289 labelSelector, fieldSelector, resourceVersion := ExtractFromListOptions(opts) 290 action.WatchRestrictions = WatchRestrictions{labelSelector, fieldSelector, resourceVersion} 291 292 return action 293} 294 295func ExtractFromListOptions(opts interface{}) (labelSelector labels.Selector, fieldSelector fields.Selector, resourceVersion string) { 296 var err error 297 switch t := opts.(type) { 298 case metav1.ListOptions: 299 labelSelector, err = labels.Parse(t.LabelSelector) 300 if err != nil { 301 panic(fmt.Errorf("invalid selector %q: %v", t.LabelSelector, err)) 302 } 303 fieldSelector, err = fields.ParseSelector(t.FieldSelector) 304 if err != nil { 305 panic(fmt.Errorf("invalid selector %q: %v", t.FieldSelector, err)) 306 } 307 resourceVersion = t.ResourceVersion 308 default: 309 panic(fmt.Errorf("expect a ListOptions %T", opts)) 310 } 311 if labelSelector == nil { 312 labelSelector = labels.Everything() 313 } 314 if fieldSelector == nil { 315 fieldSelector = fields.Everything() 316 } 317 return labelSelector, fieldSelector, resourceVersion 318} 319 320func NewWatchAction(resource schema.GroupVersionResource, namespace string, opts interface{}) WatchActionImpl { 321 action := WatchActionImpl{} 322 action.Verb = "watch" 323 action.Resource = resource 324 action.Namespace = namespace 325 labelSelector, fieldSelector, resourceVersion := ExtractFromListOptions(opts) 326 action.WatchRestrictions = WatchRestrictions{labelSelector, fieldSelector, resourceVersion} 327 328 return action 329} 330 331func NewProxyGetAction(resource schema.GroupVersionResource, namespace, scheme, name, port, path string, params map[string]string) ProxyGetActionImpl { 332 action := ProxyGetActionImpl{} 333 action.Verb = "get" 334 action.Resource = resource 335 action.Namespace = namespace 336 action.Scheme = scheme 337 action.Name = name 338 action.Port = port 339 action.Path = path 340 action.Params = params 341 return action 342} 343 344type ListRestrictions struct { 345 Labels labels.Selector 346 Fields fields.Selector 347} 348type WatchRestrictions struct { 349 Labels labels.Selector 350 Fields fields.Selector 351 ResourceVersion string 352} 353 354type Action interface { 355 GetNamespace() string 356 GetVerb() string 357 GetResource() schema.GroupVersionResource 358 GetSubresource() string 359 Matches(verb, resource string) bool 360 361 // DeepCopy is used to copy an action to avoid any risk of accidental mutation. Most people never need to call this 362 // because the invocation logic deep copies before calls to storage and reactors. 363 DeepCopy() Action 364} 365 366type GenericAction interface { 367 Action 368 GetValue() interface{} 369} 370 371type GetAction interface { 372 Action 373 GetName() string 374} 375 376type ListAction interface { 377 Action 378 GetListRestrictions() ListRestrictions 379} 380 381type CreateAction interface { 382 Action 383 GetObject() runtime.Object 384} 385 386type UpdateAction interface { 387 Action 388 GetObject() runtime.Object 389} 390 391type DeleteAction interface { 392 Action 393 GetName() string 394} 395 396type DeleteCollectionAction interface { 397 Action 398 GetListRestrictions() ListRestrictions 399} 400 401type PatchAction interface { 402 Action 403 GetName() string 404 GetPatchType() types.PatchType 405 GetPatch() []byte 406} 407 408type WatchAction interface { 409 Action 410 GetWatchRestrictions() WatchRestrictions 411} 412 413type ProxyGetAction interface { 414 Action 415 GetScheme() string 416 GetName() string 417 GetPort() string 418 GetPath() string 419 GetParams() map[string]string 420} 421 422type ActionImpl struct { 423 Namespace string 424 Verb string 425 Resource schema.GroupVersionResource 426 Subresource string 427} 428 429func (a ActionImpl) GetNamespace() string { 430 return a.Namespace 431} 432func (a ActionImpl) GetVerb() string { 433 return a.Verb 434} 435func (a ActionImpl) GetResource() schema.GroupVersionResource { 436 return a.Resource 437} 438func (a ActionImpl) GetSubresource() string { 439 return a.Subresource 440} 441func (a ActionImpl) Matches(verb, resource string) bool { 442 return strings.ToLower(verb) == strings.ToLower(a.Verb) && 443 strings.ToLower(resource) == strings.ToLower(a.Resource.Resource) 444} 445func (a ActionImpl) DeepCopy() Action { 446 ret := a 447 return ret 448} 449 450type GenericActionImpl struct { 451 ActionImpl 452 Value interface{} 453} 454 455func (a GenericActionImpl) GetValue() interface{} { 456 return a.Value 457} 458 459func (a GenericActionImpl) DeepCopy() Action { 460 return GenericActionImpl{ 461 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 462 // TODO this is wrong, but no worse than before 463 Value: a.Value, 464 } 465} 466 467type GetActionImpl struct { 468 ActionImpl 469 Name string 470} 471 472func (a GetActionImpl) GetName() string { 473 return a.Name 474} 475 476func (a GetActionImpl) DeepCopy() Action { 477 return GetActionImpl{ 478 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 479 Name: a.Name, 480 } 481} 482 483type ListActionImpl struct { 484 ActionImpl 485 Kind schema.GroupVersionKind 486 Name string 487 ListRestrictions ListRestrictions 488} 489 490func (a ListActionImpl) GetKind() schema.GroupVersionKind { 491 return a.Kind 492} 493 494func (a ListActionImpl) GetListRestrictions() ListRestrictions { 495 return a.ListRestrictions 496} 497 498func (a ListActionImpl) DeepCopy() Action { 499 return ListActionImpl{ 500 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 501 Kind: a.Kind, 502 Name: a.Name, 503 ListRestrictions: ListRestrictions{ 504 Labels: a.ListRestrictions.Labels.DeepCopySelector(), 505 Fields: a.ListRestrictions.Fields.DeepCopySelector(), 506 }, 507 } 508} 509 510type CreateActionImpl struct { 511 ActionImpl 512 Name string 513 Object runtime.Object 514} 515 516func (a CreateActionImpl) GetObject() runtime.Object { 517 return a.Object 518} 519 520func (a CreateActionImpl) DeepCopy() Action { 521 return CreateActionImpl{ 522 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 523 Name: a.Name, 524 Object: a.Object.DeepCopyObject(), 525 } 526} 527 528type UpdateActionImpl struct { 529 ActionImpl 530 Object runtime.Object 531} 532 533func (a UpdateActionImpl) GetObject() runtime.Object { 534 return a.Object 535} 536 537func (a UpdateActionImpl) DeepCopy() Action { 538 return UpdateActionImpl{ 539 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 540 Object: a.Object.DeepCopyObject(), 541 } 542} 543 544type PatchActionImpl struct { 545 ActionImpl 546 Name string 547 PatchType types.PatchType 548 Patch []byte 549} 550 551func (a PatchActionImpl) GetName() string { 552 return a.Name 553} 554 555func (a PatchActionImpl) GetPatch() []byte { 556 return a.Patch 557} 558 559func (a PatchActionImpl) GetPatchType() types.PatchType { 560 return a.PatchType 561} 562 563func (a PatchActionImpl) DeepCopy() Action { 564 patch := make([]byte, len(a.Patch)) 565 copy(patch, a.Patch) 566 return PatchActionImpl{ 567 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 568 Name: a.Name, 569 PatchType: a.PatchType, 570 Patch: patch, 571 } 572} 573 574type DeleteActionImpl struct { 575 ActionImpl 576 Name string 577} 578 579func (a DeleteActionImpl) GetName() string { 580 return a.Name 581} 582 583func (a DeleteActionImpl) DeepCopy() Action { 584 return DeleteActionImpl{ 585 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 586 Name: a.Name, 587 } 588} 589 590type DeleteCollectionActionImpl struct { 591 ActionImpl 592 ListRestrictions ListRestrictions 593} 594 595func (a DeleteCollectionActionImpl) GetListRestrictions() ListRestrictions { 596 return a.ListRestrictions 597} 598 599func (a DeleteCollectionActionImpl) DeepCopy() Action { 600 return DeleteCollectionActionImpl{ 601 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 602 ListRestrictions: ListRestrictions{ 603 Labels: a.ListRestrictions.Labels.DeepCopySelector(), 604 Fields: a.ListRestrictions.Fields.DeepCopySelector(), 605 }, 606 } 607} 608 609type WatchActionImpl struct { 610 ActionImpl 611 WatchRestrictions WatchRestrictions 612} 613 614func (a WatchActionImpl) GetWatchRestrictions() WatchRestrictions { 615 return a.WatchRestrictions 616} 617 618func (a WatchActionImpl) DeepCopy() Action { 619 return WatchActionImpl{ 620 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 621 WatchRestrictions: WatchRestrictions{ 622 Labels: a.WatchRestrictions.Labels.DeepCopySelector(), 623 Fields: a.WatchRestrictions.Fields.DeepCopySelector(), 624 ResourceVersion: a.WatchRestrictions.ResourceVersion, 625 }, 626 } 627} 628 629type ProxyGetActionImpl struct { 630 ActionImpl 631 Scheme string 632 Name string 633 Port string 634 Path string 635 Params map[string]string 636} 637 638func (a ProxyGetActionImpl) GetScheme() string { 639 return a.Scheme 640} 641 642func (a ProxyGetActionImpl) GetName() string { 643 return a.Name 644} 645 646func (a ProxyGetActionImpl) GetPort() string { 647 return a.Port 648} 649 650func (a ProxyGetActionImpl) GetPath() string { 651 return a.Path 652} 653 654func (a ProxyGetActionImpl) GetParams() map[string]string { 655 return a.Params 656} 657 658func (a ProxyGetActionImpl) DeepCopy() Action { 659 params := map[string]string{} 660 for k, v := range a.Params { 661 params[k] = v 662 } 663 return ProxyGetActionImpl{ 664 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 665 Scheme: a.Scheme, 666 Name: a.Name, 667 Port: a.Port, 668 Path: a.Path, 669 Params: params, 670 } 671} 672