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 // Stay backwards compatible. 443 if !strings.Contains(resource, "/") { 444 return strings.EqualFold(verb, a.Verb) && 445 strings.EqualFold(resource, a.Resource.Resource) 446 } 447 448 parts := strings.SplitN(resource, "/", 2) 449 topresource, subresource := parts[0], parts[1] 450 451 return strings.EqualFold(verb, a.Verb) && 452 strings.EqualFold(topresource, a.Resource.Resource) && 453 strings.EqualFold(subresource, a.Subresource) 454} 455func (a ActionImpl) DeepCopy() Action { 456 ret := a 457 return ret 458} 459 460type GenericActionImpl struct { 461 ActionImpl 462 Value interface{} 463} 464 465func (a GenericActionImpl) GetValue() interface{} { 466 return a.Value 467} 468 469func (a GenericActionImpl) DeepCopy() Action { 470 return GenericActionImpl{ 471 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 472 // TODO this is wrong, but no worse than before 473 Value: a.Value, 474 } 475} 476 477type GetActionImpl struct { 478 ActionImpl 479 Name string 480} 481 482func (a GetActionImpl) GetName() string { 483 return a.Name 484} 485 486func (a GetActionImpl) DeepCopy() Action { 487 return GetActionImpl{ 488 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 489 Name: a.Name, 490 } 491} 492 493type ListActionImpl struct { 494 ActionImpl 495 Kind schema.GroupVersionKind 496 Name string 497 ListRestrictions ListRestrictions 498} 499 500func (a ListActionImpl) GetKind() schema.GroupVersionKind { 501 return a.Kind 502} 503 504func (a ListActionImpl) GetListRestrictions() ListRestrictions { 505 return a.ListRestrictions 506} 507 508func (a ListActionImpl) DeepCopy() Action { 509 return ListActionImpl{ 510 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 511 Kind: a.Kind, 512 Name: a.Name, 513 ListRestrictions: ListRestrictions{ 514 Labels: a.ListRestrictions.Labels.DeepCopySelector(), 515 Fields: a.ListRestrictions.Fields.DeepCopySelector(), 516 }, 517 } 518} 519 520type CreateActionImpl struct { 521 ActionImpl 522 Name string 523 Object runtime.Object 524} 525 526func (a CreateActionImpl) GetObject() runtime.Object { 527 return a.Object 528} 529 530func (a CreateActionImpl) DeepCopy() Action { 531 return CreateActionImpl{ 532 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 533 Name: a.Name, 534 Object: a.Object.DeepCopyObject(), 535 } 536} 537 538type UpdateActionImpl struct { 539 ActionImpl 540 Object runtime.Object 541} 542 543func (a UpdateActionImpl) GetObject() runtime.Object { 544 return a.Object 545} 546 547func (a UpdateActionImpl) DeepCopy() Action { 548 return UpdateActionImpl{ 549 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 550 Object: a.Object.DeepCopyObject(), 551 } 552} 553 554type PatchActionImpl struct { 555 ActionImpl 556 Name string 557 PatchType types.PatchType 558 Patch []byte 559} 560 561func (a PatchActionImpl) GetName() string { 562 return a.Name 563} 564 565func (a PatchActionImpl) GetPatch() []byte { 566 return a.Patch 567} 568 569func (a PatchActionImpl) GetPatchType() types.PatchType { 570 return a.PatchType 571} 572 573func (a PatchActionImpl) DeepCopy() Action { 574 patch := make([]byte, len(a.Patch)) 575 copy(patch, a.Patch) 576 return PatchActionImpl{ 577 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 578 Name: a.Name, 579 PatchType: a.PatchType, 580 Patch: patch, 581 } 582} 583 584type DeleteActionImpl struct { 585 ActionImpl 586 Name string 587} 588 589func (a DeleteActionImpl) GetName() string { 590 return a.Name 591} 592 593func (a DeleteActionImpl) DeepCopy() Action { 594 return DeleteActionImpl{ 595 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 596 Name: a.Name, 597 } 598} 599 600type DeleteCollectionActionImpl struct { 601 ActionImpl 602 ListRestrictions ListRestrictions 603} 604 605func (a DeleteCollectionActionImpl) GetListRestrictions() ListRestrictions { 606 return a.ListRestrictions 607} 608 609func (a DeleteCollectionActionImpl) DeepCopy() Action { 610 return DeleteCollectionActionImpl{ 611 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 612 ListRestrictions: ListRestrictions{ 613 Labels: a.ListRestrictions.Labels.DeepCopySelector(), 614 Fields: a.ListRestrictions.Fields.DeepCopySelector(), 615 }, 616 } 617} 618 619type WatchActionImpl struct { 620 ActionImpl 621 WatchRestrictions WatchRestrictions 622} 623 624func (a WatchActionImpl) GetWatchRestrictions() WatchRestrictions { 625 return a.WatchRestrictions 626} 627 628func (a WatchActionImpl) DeepCopy() Action { 629 return WatchActionImpl{ 630 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 631 WatchRestrictions: WatchRestrictions{ 632 Labels: a.WatchRestrictions.Labels.DeepCopySelector(), 633 Fields: a.WatchRestrictions.Fields.DeepCopySelector(), 634 ResourceVersion: a.WatchRestrictions.ResourceVersion, 635 }, 636 } 637} 638 639type ProxyGetActionImpl struct { 640 ActionImpl 641 Scheme string 642 Name string 643 Port string 644 Path string 645 Params map[string]string 646} 647 648func (a ProxyGetActionImpl) GetScheme() string { 649 return a.Scheme 650} 651 652func (a ProxyGetActionImpl) GetName() string { 653 return a.Name 654} 655 656func (a ProxyGetActionImpl) GetPort() string { 657 return a.Port 658} 659 660func (a ProxyGetActionImpl) GetPath() string { 661 return a.Path 662} 663 664func (a ProxyGetActionImpl) GetParams() map[string]string { 665 return a.Params 666} 667 668func (a ProxyGetActionImpl) DeepCopy() Action { 669 params := map[string]string{} 670 for k, v := range a.Params { 671 params[k] = v 672 } 673 return ProxyGetActionImpl{ 674 ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl), 675 Scheme: a.Scheme, 676 Name: a.Name, 677 Port: a.Port, 678 Path: a.Path, 679 Params: params, 680 } 681} 682