create.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. Copyright 2018 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package framework
  14. import (
  15. "bytes"
  16. "encoding/json"
  17. "fmt"
  18. "github.com/pkg/errors"
  19. apps "k8s.io/api/apps/v1"
  20. "k8s.io/api/core/v1"
  21. rbac "k8s.io/api/rbac/v1"
  22. storage "k8s.io/api/storage/v1"
  23. apierrs "k8s.io/apimachinery/pkg/api/errors"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. "k8s.io/apimachinery/pkg/runtime"
  26. "k8s.io/apimachinery/pkg/runtime/schema"
  27. "k8s.io/client-go/kubernetes/scheme"
  28. "k8s.io/client-go/tools/cache"
  29. e2elog "k8s.io/kubernetes/test/e2e/framework/log"
  30. "k8s.io/kubernetes/test/e2e/framework/testfiles"
  31. )
  32. // LoadFromManifests loads .yaml or .json manifest files and returns
  33. // all items that it finds in them. It supports all items for which
  34. // there is a factory registered in factories and .yaml files with
  35. // multiple items separated by "---". Files are accessed via the
  36. // "testfiles" package, which means they can come from a file system
  37. // or be built into the binary.
  38. //
  39. // LoadFromManifests has some limitations:
  40. // - aliases are not supported (i.e. use serviceAccountName instead of the deprecated serviceAccount,
  41. // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#podspec-v1-core)
  42. // and silently ignored
  43. // - the latest stable API version for each item is used, regardless of what
  44. // is specified in the manifest files
  45. func (f *Framework) LoadFromManifests(files ...string) ([]interface{}, error) {
  46. var items []interface{}
  47. err := visitManifests(func(data []byte) error {
  48. // Ignore any additional fields for now, just determine what we have.
  49. var what What
  50. if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), data, &what); err != nil {
  51. return errors.Wrap(err, "decode TypeMeta")
  52. }
  53. factory := factories[what]
  54. if factory == nil {
  55. return errors.Errorf("item of type %+v not supported", what)
  56. }
  57. object := factory.New()
  58. if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), data, object); err != nil {
  59. return errors.Wrapf(err, "decode %+v", what)
  60. }
  61. items = append(items, object)
  62. return nil
  63. }, files...)
  64. return items, err
  65. }
  66. func visitManifests(cb func([]byte) error, files ...string) error {
  67. for _, fileName := range files {
  68. data, err := testfiles.Read(fileName)
  69. if err != nil {
  70. Failf("reading manifest file: %v", err)
  71. }
  72. // Split at the "---" separator before working on
  73. // individual item. Only works for .yaml.
  74. //
  75. // We need to split ourselves because we need access
  76. // to each original chunk of data for
  77. // runtime.DecodeInto. kubectl has its own
  78. // infrastructure for this, but that is a lot of code
  79. // with many dependencies.
  80. items := bytes.Split(data, []byte("\n---"))
  81. for _, item := range items {
  82. if err := cb(item); err != nil {
  83. return errors.Wrap(err, fileName)
  84. }
  85. }
  86. }
  87. return nil
  88. }
  89. // PatchItems modifies the given items in place such that each test
  90. // gets its own instances, to avoid conflicts between different tests
  91. // and between tests and normal deployments.
  92. //
  93. // This is done by:
  94. // - creating namespaced items inside the test's namespace
  95. // - changing the name of non-namespaced items like ClusterRole
  96. //
  97. // PatchItems has some limitations:
  98. // - only some common items are supported, unknown ones trigger an error
  99. // - only the latest stable API version for each item is supported
  100. func (f *Framework) PatchItems(items ...interface{}) error {
  101. for _, item := range items {
  102. // Uncomment when debugging the loading and patching of items.
  103. // e2elog.Logf("patching original content of %T:\n%s", item, PrettyPrint(item))
  104. if err := f.patchItemRecursively(item); err != nil {
  105. return err
  106. }
  107. }
  108. return nil
  109. }
  110. // CreateItems creates the items. Each of them must be an API object
  111. // of a type that is registered in Factory.
  112. //
  113. // It returns either a cleanup function or an error, but never both.
  114. //
  115. // Cleaning up after a test can be triggered in two ways:
  116. // - the test invokes the returned cleanup function,
  117. // usually in an AfterEach
  118. // - the test suite terminates, potentially after
  119. // skipping the test's AfterEach (https://github.com/onsi/ginkgo/issues/222)
  120. //
  121. // PatchItems has the some limitations as LoadFromManifests:
  122. // - only some common items are supported, unknown ones trigger an error
  123. // - only the latest stable API version for each item is supported
  124. func (f *Framework) CreateItems(items ...interface{}) (func(), error) {
  125. var destructors []func() error
  126. var cleanupHandle CleanupActionHandle
  127. cleanup := func() {
  128. if cleanupHandle == nil {
  129. // Already done.
  130. return
  131. }
  132. RemoveCleanupAction(cleanupHandle)
  133. // TODO (?): use same logic as framework.go for determining
  134. // whether we are expected to clean up? This would change the
  135. // meaning of the -delete-namespace and -delete-namespace-on-failure
  136. // command line flags, because they would also start to apply
  137. // to non-namespaced items.
  138. for _, destructor := range destructors {
  139. if err := destructor(); err != nil && !apierrs.IsNotFound(err) {
  140. e2elog.Logf("deleting failed: %s", err)
  141. }
  142. }
  143. }
  144. cleanupHandle = AddCleanupAction(cleanup)
  145. var result error
  146. for _, item := range items {
  147. // Each factory knows which item(s) it supports, so try each one.
  148. done := false
  149. description := DescribeItem(item)
  150. // Uncomment this line to get a full dump of the entire item.
  151. // description = fmt.Sprintf("%s:\n%s", description, PrettyPrint(item))
  152. e2elog.Logf("creating %s", description)
  153. for _, factory := range factories {
  154. destructor, err := factory.Create(f, item)
  155. if destructor != nil {
  156. destructors = append(destructors, func() error {
  157. e2elog.Logf("deleting %s", description)
  158. return destructor()
  159. })
  160. }
  161. if err == nil {
  162. done = true
  163. break
  164. } else if errors.Cause(err) != errorItemNotSupported {
  165. result = err
  166. break
  167. }
  168. }
  169. if result == nil && !done {
  170. result = errors.Errorf("item of type %T not supported", item)
  171. break
  172. }
  173. }
  174. if result != nil {
  175. cleanup()
  176. return nil, result
  177. }
  178. return cleanup, nil
  179. }
  180. // CreateFromManifests is a combination of LoadFromManifests,
  181. // PatchItems, patching with an optional custom function,
  182. // and CreateItems.
  183. func (f *Framework) CreateFromManifests(patch func(item interface{}) error, files ...string) (func(), error) {
  184. items, err := f.LoadFromManifests(files...)
  185. if err != nil {
  186. return nil, errors.Wrap(err, "CreateFromManifests")
  187. }
  188. if err := f.PatchItems(items...); err != nil {
  189. return nil, err
  190. }
  191. if patch != nil {
  192. for _, item := range items {
  193. if err := patch(item); err != nil {
  194. return nil, err
  195. }
  196. }
  197. }
  198. return f.CreateItems(items...)
  199. }
  200. // What is a subset of metav1.TypeMeta which (in contrast to
  201. // metav1.TypeMeta itself) satisfies the runtime.Object interface.
  202. type What struct {
  203. Kind string `json:"kind"`
  204. }
  205. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new What.
  206. func (in *What) DeepCopy() *What {
  207. return &What{Kind: in.Kind}
  208. }
  209. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out.
  210. func (in *What) DeepCopyInto(out *What) {
  211. out.Kind = in.Kind
  212. }
  213. // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
  214. func (in *What) DeepCopyObject() runtime.Object {
  215. return &What{Kind: in.Kind}
  216. }
  217. // GetObjectKind returns the ObjectKind schema
  218. func (in *What) GetObjectKind() schema.ObjectKind {
  219. return nil
  220. }
  221. // ItemFactory provides support for creating one particular item.
  222. // The type gets exported because other packages might want to
  223. // extend the set of pre-defined factories.
  224. type ItemFactory interface {
  225. // New returns a new empty item.
  226. New() runtime.Object
  227. // Create is responsible for creating the item. It returns an
  228. // error or a cleanup function for the created item.
  229. // If the item is of an unsupported type, it must return
  230. // an error that has errorItemNotSupported as cause.
  231. Create(f *Framework, item interface{}) (func() error, error)
  232. }
  233. // DescribeItem always returns a string that describes the item,
  234. // usually by calling out to cache.MetaNamespaceKeyFunc which
  235. // concatenates namespace (if set) and name. If that fails, the entire
  236. // item gets converted to a string.
  237. func DescribeItem(item interface{}) string {
  238. key, err := cache.MetaNamespaceKeyFunc(item)
  239. if err == nil && key != "" {
  240. return fmt.Sprintf("%T: %s", item, key)
  241. }
  242. return fmt.Sprintf("%T: %s", item, item)
  243. }
  244. // errorItemNotSupported is the error that Create methods
  245. // must return or wrap when they don't support the given item.
  246. var errorItemNotSupported = errors.New("not supported")
  247. var factories = map[What]ItemFactory{
  248. {"ClusterRole"}: &clusterRoleFactory{},
  249. {"ClusterRoleBinding"}: &clusterRoleBindingFactory{},
  250. {"DaemonSet"}: &daemonSetFactory{},
  251. {"Role"}: &roleFactory{},
  252. {"RoleBinding"}: &roleBindingFactory{},
  253. {"Secret"}: &secretFactory{},
  254. {"Service"}: &serviceFactory{},
  255. {"ServiceAccount"}: &serviceAccountFactory{},
  256. {"StatefulSet"}: &statefulSetFactory{},
  257. {"StorageClass"}: &storageClassFactory{},
  258. }
  259. // PatchName makes the name of some item unique by appending the
  260. // generated unique name.
  261. func (f *Framework) PatchName(item *string) {
  262. if *item != "" {
  263. *item = *item + "-" + f.UniqueName
  264. }
  265. }
  266. // PatchNamespace moves the item into the test's namespace. Not
  267. // all items can be namespaced. For those, the name also needs to be
  268. // patched.
  269. func (f *Framework) PatchNamespace(item *string) {
  270. if f.Namespace != nil {
  271. *item = f.Namespace.GetName()
  272. }
  273. }
  274. func (f *Framework) patchItemRecursively(item interface{}) error {
  275. switch item := item.(type) {
  276. case *rbac.Subject:
  277. f.PatchNamespace(&item.Namespace)
  278. case *rbac.RoleRef:
  279. // TODO: avoid hard-coding this special name. Perhaps add a Framework.PredefinedRoles
  280. // which contains all role names that are defined cluster-wide before the test starts?
  281. // All those names are excempt from renaming. That list could be populated by querying
  282. // and get extended by tests.
  283. if item.Name != "e2e-test-privileged-psp" {
  284. f.PatchName(&item.Name)
  285. }
  286. case *rbac.ClusterRole:
  287. f.PatchName(&item.Name)
  288. case *rbac.Role:
  289. f.PatchNamespace(&item.Namespace)
  290. // Roles are namespaced, but because for RoleRef above we don't
  291. // know whether the referenced role is a ClusterRole or Role
  292. // and therefore always renames, we have to do the same here.
  293. f.PatchName(&item.Name)
  294. case *storage.StorageClass:
  295. f.PatchName(&item.Name)
  296. case *v1.ServiceAccount:
  297. f.PatchNamespace(&item.ObjectMeta.Namespace)
  298. case *v1.Secret:
  299. f.PatchNamespace(&item.ObjectMeta.Namespace)
  300. case *rbac.ClusterRoleBinding:
  301. f.PatchName(&item.Name)
  302. for i := range item.Subjects {
  303. if err := f.patchItemRecursively(&item.Subjects[i]); err != nil {
  304. return errors.Wrapf(err, "%T", f)
  305. }
  306. }
  307. if err := f.patchItemRecursively(&item.RoleRef); err != nil {
  308. return errors.Wrapf(err, "%T", f)
  309. }
  310. case *rbac.RoleBinding:
  311. f.PatchNamespace(&item.Namespace)
  312. for i := range item.Subjects {
  313. if err := f.patchItemRecursively(&item.Subjects[i]); err != nil {
  314. return errors.Wrapf(err, "%T", f)
  315. }
  316. }
  317. if err := f.patchItemRecursively(&item.RoleRef); err != nil {
  318. return errors.Wrapf(err, "%T", f)
  319. }
  320. case *v1.Service:
  321. f.PatchNamespace(&item.ObjectMeta.Namespace)
  322. case *apps.StatefulSet:
  323. f.PatchNamespace(&item.ObjectMeta.Namespace)
  324. case *apps.DaemonSet:
  325. f.PatchNamespace(&item.ObjectMeta.Namespace)
  326. default:
  327. return errors.Errorf("missing support for patching item of type %T", item)
  328. }
  329. return nil
  330. }
  331. // The individual factories all follow the same template, but with
  332. // enough differences in types and functions that copy-and-paste
  333. // looked like the least dirty approach. Perhaps one day Go will have
  334. // generics.
  335. type serviceAccountFactory struct{}
  336. func (f *serviceAccountFactory) New() runtime.Object {
  337. return &v1.ServiceAccount{}
  338. }
  339. func (*serviceAccountFactory) Create(f *Framework, i interface{}) (func() error, error) {
  340. item, ok := i.(*v1.ServiceAccount)
  341. if !ok {
  342. return nil, errorItemNotSupported
  343. }
  344. client := f.ClientSet.CoreV1().ServiceAccounts(f.Namespace.GetName())
  345. if _, err := client.Create(item); err != nil {
  346. return nil, errors.Wrap(err, "create ServiceAccount")
  347. }
  348. return func() error {
  349. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  350. }, nil
  351. }
  352. type clusterRoleFactory struct{}
  353. func (f *clusterRoleFactory) New() runtime.Object {
  354. return &rbac.ClusterRole{}
  355. }
  356. func (*clusterRoleFactory) Create(f *Framework, i interface{}) (func() error, error) {
  357. item, ok := i.(*rbac.ClusterRole)
  358. if !ok {
  359. return nil, errorItemNotSupported
  360. }
  361. e2elog.Logf("Define cluster role %v", item.GetName())
  362. client := f.ClientSet.RbacV1().ClusterRoles()
  363. if _, err := client.Create(item); err != nil {
  364. return nil, errors.Wrap(err, "create ClusterRole")
  365. }
  366. return func() error {
  367. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  368. }, nil
  369. }
  370. type clusterRoleBindingFactory struct{}
  371. func (f *clusterRoleBindingFactory) New() runtime.Object {
  372. return &rbac.ClusterRoleBinding{}
  373. }
  374. func (*clusterRoleBindingFactory) Create(f *Framework, i interface{}) (func() error, error) {
  375. item, ok := i.(*rbac.ClusterRoleBinding)
  376. if !ok {
  377. return nil, errorItemNotSupported
  378. }
  379. client := f.ClientSet.RbacV1().ClusterRoleBindings()
  380. if _, err := client.Create(item); err != nil {
  381. return nil, errors.Wrap(err, "create ClusterRoleBinding")
  382. }
  383. return func() error {
  384. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  385. }, nil
  386. }
  387. type roleFactory struct{}
  388. func (f *roleFactory) New() runtime.Object {
  389. return &rbac.Role{}
  390. }
  391. func (*roleFactory) Create(f *Framework, i interface{}) (func() error, error) {
  392. item, ok := i.(*rbac.Role)
  393. if !ok {
  394. return nil, errorItemNotSupported
  395. }
  396. client := f.ClientSet.RbacV1().Roles(f.Namespace.GetName())
  397. if _, err := client.Create(item); err != nil {
  398. return nil, errors.Wrap(err, "create Role")
  399. }
  400. return func() error {
  401. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  402. }, nil
  403. }
  404. type roleBindingFactory struct{}
  405. func (f *roleBindingFactory) New() runtime.Object {
  406. return &rbac.RoleBinding{}
  407. }
  408. func (*roleBindingFactory) Create(f *Framework, i interface{}) (func() error, error) {
  409. item, ok := i.(*rbac.RoleBinding)
  410. if !ok {
  411. return nil, errorItemNotSupported
  412. }
  413. client := f.ClientSet.RbacV1().RoleBindings(f.Namespace.GetName())
  414. if _, err := client.Create(item); err != nil {
  415. return nil, errors.Wrap(err, "create RoleBinding")
  416. }
  417. return func() error {
  418. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  419. }, nil
  420. }
  421. type serviceFactory struct{}
  422. func (f *serviceFactory) New() runtime.Object {
  423. return &v1.Service{}
  424. }
  425. func (*serviceFactory) Create(f *Framework, i interface{}) (func() error, error) {
  426. item, ok := i.(*v1.Service)
  427. if !ok {
  428. return nil, errorItemNotSupported
  429. }
  430. client := f.ClientSet.CoreV1().Services(f.Namespace.GetName())
  431. if _, err := client.Create(item); err != nil {
  432. return nil, errors.Wrap(err, "create Service")
  433. }
  434. return func() error {
  435. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  436. }, nil
  437. }
  438. type statefulSetFactory struct{}
  439. func (f *statefulSetFactory) New() runtime.Object {
  440. return &apps.StatefulSet{}
  441. }
  442. func (*statefulSetFactory) Create(f *Framework, i interface{}) (func() error, error) {
  443. item, ok := i.(*apps.StatefulSet)
  444. if !ok {
  445. return nil, errorItemNotSupported
  446. }
  447. client := f.ClientSet.AppsV1().StatefulSets(f.Namespace.GetName())
  448. if _, err := client.Create(item); err != nil {
  449. return nil, errors.Wrap(err, "create StatefulSet")
  450. }
  451. return func() error {
  452. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  453. }, nil
  454. }
  455. type daemonSetFactory struct{}
  456. func (f *daemonSetFactory) New() runtime.Object {
  457. return &apps.DaemonSet{}
  458. }
  459. func (*daemonSetFactory) Create(f *Framework, i interface{}) (func() error, error) {
  460. item, ok := i.(*apps.DaemonSet)
  461. if !ok {
  462. return nil, errorItemNotSupported
  463. }
  464. client := f.ClientSet.AppsV1().DaemonSets(f.Namespace.GetName())
  465. if _, err := client.Create(item); err != nil {
  466. return nil, errors.Wrap(err, "create DaemonSet")
  467. }
  468. return func() error {
  469. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  470. }, nil
  471. }
  472. type storageClassFactory struct{}
  473. func (f *storageClassFactory) New() runtime.Object {
  474. return &storage.StorageClass{}
  475. }
  476. func (*storageClassFactory) Create(f *Framework, i interface{}) (func() error, error) {
  477. item, ok := i.(*storage.StorageClass)
  478. if !ok {
  479. return nil, errorItemNotSupported
  480. }
  481. client := f.ClientSet.StorageV1().StorageClasses()
  482. if _, err := client.Create(item); err != nil {
  483. return nil, errors.Wrap(err, "create StorageClass")
  484. }
  485. return func() error {
  486. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  487. }, nil
  488. }
  489. type secretFactory struct{}
  490. func (f *secretFactory) New() runtime.Object {
  491. return &v1.Secret{}
  492. }
  493. func (*secretFactory) Create(f *Framework, i interface{}) (func() error, error) {
  494. item, ok := i.(*v1.Secret)
  495. if !ok {
  496. return nil, errorItemNotSupported
  497. }
  498. client := f.ClientSet.CoreV1().Secrets(f.Namespace.GetName())
  499. if _, err := client.Create(item); err != nil {
  500. return nil, errors.Wrap(err, "create Secret")
  501. }
  502. return func() error {
  503. return client.Delete(item.GetName(), &metav1.DeleteOptions{})
  504. }, nil
  505. }
  506. // PrettyPrint returns a human-readable representation of an item.
  507. func PrettyPrint(item interface{}) string {
  508. data, err := json.MarshalIndent(item, "", " ")
  509. if err == nil {
  510. return string(data)
  511. }
  512. return fmt.Sprintf("%+v", item)
  513. }