github.com/jenkins-x/jx/v2@v2.1.155/pkg/kube/crds.go (about)

     1  package kube
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"time"
     8  
     9  	openapi "github.com/jenkins-x/jx-api/pkg/client/openapi/all"
    10  
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	"k8s.io/kube-openapi/pkg/common"
    13  
    14  	"github.com/go-openapi/jsonreference"
    15  
    16  	"github.com/jenkins-x/jx-logging/pkg/log"
    17  
    18  	"github.com/go-openapi/spec"
    19  	"github.com/pkg/errors"
    20  
    21  	"github.com/cenkalti/backoff"
    22  	jenkinsio "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io"
    23  	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
    24  	apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
    25  )
    26  
    27  // RegisterAllCRDs ensures that all Jenkins-X CRDs are registered
    28  func RegisterAllCRDs(apiClient apiextensionsclientset.Interface) error {
    29  	err := RegisterCommitStatusCRD(apiClient)
    30  	if err != nil {
    31  		return errors.Wrap(err, "failed to register the Commit Status CRD")
    32  	}
    33  	err = RegisterExtensionCRD(apiClient)
    34  	if err != nil {
    35  		return errors.Wrap(err, "failed to register the Extension CRD")
    36  	}
    37  	err = RegisterAppCRD(apiClient)
    38  	if err != nil {
    39  		return errors.Wrap(err, "failed to register the App CRD")
    40  	}
    41  	err = RegisterPluginCRD(apiClient)
    42  	if err != nil {
    43  		return errors.Wrap(err, "failed to register the Plugin CRD")
    44  	}
    45  	err = RegisterEnvironmentRoleBindingCRD(apiClient)
    46  	if err != nil {
    47  		return errors.Wrap(err, "failed to register the Environment Role Binding CRD")
    48  	}
    49  	err = RegisterGitServiceCRD(apiClient)
    50  	if err != nil {
    51  		return errors.Wrap(err, "failed to register the Git Service CRD")
    52  	}
    53  	err = RegisterFactCRD(apiClient)
    54  	if err != nil {
    55  		return errors.Wrap(err, "failed to register the Fact CRD")
    56  	}
    57  	err = RegisterTeamCRD(apiClient)
    58  	if err != nil {
    59  		return errors.Wrap(err, "failed to register the Team CRD")
    60  	}
    61  	err = RegisterUserCRD(apiClient)
    62  	if err != nil {
    63  		return errors.Wrap(err, "failed to register the User CRD")
    64  	}
    65  	err = RegisterWorkflowCRD(apiClient)
    66  	if err != nil {
    67  		return errors.Wrap(err, "failed to register the Workflow CRD")
    68  	}
    69  
    70  	return RegisterPipelineCRDs(apiClient)
    71  }
    72  
    73  // RegisterPipelineCRDs ensures that all Jenkins X Pipeline related CRDs are registered
    74  func RegisterPipelineCRDs(apiClient apiextensionsclientset.Interface) error {
    75  	err := RegisterBuildPackCRD(apiClient)
    76  	if err != nil {
    77  		return errors.Wrap(err, "failed to register the Build Pack CRD")
    78  	}
    79  	err = RegisterEnvironmentCRD(apiClient)
    80  	if err != nil {
    81  		return errors.Wrap(err, "failed to register the Environment CRD")
    82  	}
    83  	err = RegisterReleaseCRD(apiClient)
    84  	if err != nil {
    85  		return errors.Wrap(err, "failed to register the Release CRD")
    86  	}
    87  	err = RegisterPipelineActivityCRD(apiClient)
    88  	if err != nil {
    89  		return errors.Wrap(err, "failed to register the Pipeline Activity CRD")
    90  	}
    91  	err = RegisterPipelineStructureCRD(apiClient)
    92  	if err != nil {
    93  		return errors.Wrap(err, "failed to register the Pipeline Structure CRD")
    94  	}
    95  	err = RegisterPluginCRD(apiClient)
    96  	if err != nil {
    97  		return errors.Wrap(err, "failed to register the Plugin CRD")
    98  	}
    99  	err = RegisterSourceRepositoryCRD(apiClient)
   100  	if err != nil {
   101  		return errors.Wrap(err, "failed to register the SourceRepository CRD")
   102  	}
   103  	err = RegisterPipelineScheduler(apiClient)
   104  	if err != nil {
   105  		return errors.Wrap(err, "failed to register the PipelineScheduler CRD")
   106  	}
   107  	err = RegisterSourceRepositoryGroup(apiClient)
   108  	if err != nil {
   109  		return errors.Wrap(err, "failed to register the RegisterSourceRepositoryGroup CRD")
   110  	}
   111  	return nil
   112  }
   113  
   114  // RegisterEnvironmentCRD ensures that the CRD is registered for Environments
   115  func RegisterEnvironmentCRD(apiClient apiextensionsclientset.Interface) error {
   116  	name := "environments." + jenkinsio.GroupName
   117  	names := &v1beta1.CustomResourceDefinitionNames{
   118  		Kind:       "Environment",
   119  		ListKind:   "EnvironmentList",
   120  		Plural:     "environments",
   121  		Singular:   "environment",
   122  		ShortNames: []string{"env"},
   123  	}
   124  	columns := []v1beta1.CustomResourceColumnDefinition{
   125  		{
   126  			Name:        "Namespace",
   127  			Type:        "string",
   128  			Description: "The namespace used for the environment",
   129  			JSONPath:    ".spec.namespace",
   130  		},
   131  		{
   132  			Name:        "Kind",
   133  			Type:        "string",
   134  			Description: "The kind of environment",
   135  			JSONPath:    ".spec.kind",
   136  		},
   137  		{
   138  			Name:        "Promotion",
   139  			Type:        "string",
   140  			Description: "The strategy used for promoting to this environment",
   141  			JSONPath:    ".spec.promotionStrategy",
   142  		},
   143  		{
   144  			Name:        "Order",
   145  			Type:        "integer",
   146  			Description: "The order in which environments are automatically promoted",
   147  			JSONPath:    ".spec.order",
   148  		},
   149  		{
   150  			Name:        "Git URL",
   151  			Type:        "string",
   152  			Description: "The Git repository URL for the source of the environment configuration",
   153  			JSONPath:    ".spec.source.url",
   154  		},
   155  		{
   156  			Name:        "Git Branch",
   157  			Type:        "string",
   158  			Description: "The git branch for the source of the environment configuration",
   159  			JSONPath:    ".spec.source.ref",
   160  		},
   161  	}
   162  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   163  }
   164  
   165  // RegisterEnvironmentRoleBindingCRD ensures that the CRD is registered for Environments
   166  func RegisterEnvironmentRoleBindingCRD(apiClient apiextensionsclientset.Interface) error {
   167  	name := "environmentrolebindings." + jenkinsio.GroupName
   168  	names := &v1beta1.CustomResourceDefinitionNames{
   169  		Kind:       "EnvironmentRoleBinding",
   170  		ListKind:   "EnvironmentRoleBindingList",
   171  		Plural:     "environmentrolebindings",
   172  		Singular:   "environmentrolebinding",
   173  		ShortNames: []string{"envrolebindings", "envrolebinding", "envrb", "erb"},
   174  		Categories: []string{"all"},
   175  	}
   176  	columns := []v1beta1.CustomResourceColumnDefinition{}
   177  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   178  }
   179  
   180  // RegisterGitServiceCRD ensures that the CRD is registered for GitServices
   181  func RegisterGitServiceCRD(apiClient apiextensionsclientset.Interface) error {
   182  	name := "gitservices." + jenkinsio.GroupName
   183  	names := &v1beta1.CustomResourceDefinitionNames{
   184  		Kind:       "GitService",
   185  		ListKind:   "GitServiceList",
   186  		Plural:     "gitservices",
   187  		Singular:   "gitservice",
   188  		ShortNames: []string{"gits", "gs"},
   189  		Categories: []string{"all"},
   190  	}
   191  	columns := []v1beta1.CustomResourceColumnDefinition{
   192  		{
   193  			Name:        "Git URL",
   194  			Type:        "string",
   195  			Description: "The URL of the Git repository",
   196  			JSONPath:    ".spec.url",
   197  		},
   198  		{
   199  			Name:        "Kind",
   200  			Type:        "string",
   201  			Description: "The kind of the Git provider",
   202  			JSONPath:    ".spec.gitKind",
   203  		},
   204  	}
   205  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   206  }
   207  
   208  // RegisterPipelineActivityCRD ensures that the CRD is registered for PipelineActivity
   209  func RegisterPipelineActivityCRD(apiClient apiextensionsclientset.Interface) error {
   210  	name := "pipelineactivities." + jenkinsio.GroupName
   211  	names := &v1beta1.CustomResourceDefinitionNames{
   212  		Kind:       "PipelineActivity",
   213  		ListKind:   "PipelineActivityList",
   214  		Plural:     "pipelineactivities",
   215  		Singular:   "pipelineactivity",
   216  		ShortNames: []string{"activity", "act", "pa"},
   217  		Categories: []string{"all"},
   218  	}
   219  	columns := []v1beta1.CustomResourceColumnDefinition{
   220  		{
   221  			Name:        "Git URL",
   222  			Type:        "string",
   223  			Description: "The URL of the Git repository",
   224  			JSONPath:    ".spec.gitUrl",
   225  		},
   226  		{
   227  			Name:        "Status",
   228  			Type:        "string",
   229  			Description: "The status of the pipeline",
   230  			JSONPath:    ".spec.status",
   231  		},
   232  	}
   233  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   234  }
   235  
   236  // RegisterPipelineStructureCRD ensures that the CRD is registered for PipelineStructure
   237  func RegisterPipelineStructureCRD(apiClient apiextensionsclientset.Interface) error {
   238  	name := "pipelinestructures." + jenkinsio.GroupName
   239  	names := &v1beta1.CustomResourceDefinitionNames{
   240  		Kind:       "PipelineStructure",
   241  		ListKind:   "PipelineStructureList",
   242  		Plural:     "pipelinestructures",
   243  		Singular:   "pipelinestructure",
   244  		ShortNames: []string{"structure", "ps"},
   245  		Categories: []string{"all"},
   246  	}
   247  	columns := []v1beta1.CustomResourceColumnDefinition{}
   248  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   249  }
   250  
   251  // RegisterFactCRD ensures that the CRD is registered for Fact
   252  func RegisterFactCRD(apiClient apiextensionsclientset.Interface) error {
   253  	name := "facts." + jenkinsio.GroupName
   254  	names := &v1beta1.CustomResourceDefinitionNames{
   255  		Kind:       "Fact",
   256  		ListKind:   "FactList",
   257  		Plural:     "facts",
   258  		Singular:   "fact",
   259  		ShortNames: []string{"fact"},
   260  		Categories: []string{"all"},
   261  	}
   262  	columns := []v1beta1.CustomResourceColumnDefinition{
   263  		{
   264  			Name:        "Name",
   265  			Type:        "string",
   266  			Description: "The name of the fact",
   267  			JSONPath:    ".spec.name",
   268  		},
   269  		{
   270  			Name:        "Type",
   271  			Type:        "string",
   272  			Description: "The type of the fact",
   273  			JSONPath:    ".spec.factType",
   274  		},
   275  	}
   276  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   277  }
   278  
   279  // RegisterExtensionCRD ensures that the CRD is registered for Extension
   280  func RegisterExtensionCRD(apiClient apiextensionsclientset.Interface) error {
   281  	name := "extensions." + jenkinsio.GroupName
   282  	names := &v1beta1.CustomResourceDefinitionNames{
   283  		Kind:       "Extension",
   284  		ListKind:   "ExtensionList",
   285  		Plural:     "extensions",
   286  		Singular:   "extensions",
   287  		ShortNames: []string{"extension", "ext"},
   288  		Categories: []string{"all"},
   289  	}
   290  	columns := []v1beta1.CustomResourceColumnDefinition{
   291  		{
   292  			Name:        "Name",
   293  			Type:        "string",
   294  			Description: "The name of the extension",
   295  			JSONPath:    ".spec.name",
   296  		},
   297  		{
   298  			Name:        "Description",
   299  			Type:        "string",
   300  			Description: "A description of the extension",
   301  			JSONPath:    ".spec.description",
   302  		},
   303  	}
   304  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   305  }
   306  
   307  // RegisterBuildPackCRD ensures that the CRD is registered for BuildPack
   308  func RegisterBuildPackCRD(apiClient apiextensionsclientset.Interface) error {
   309  	name := "buildpacks." + jenkinsio.GroupName
   310  	names := &v1beta1.CustomResourceDefinitionNames{
   311  		Kind:       "BuildPack",
   312  		ListKind:   "BuildPackList",
   313  		Plural:     "buildpacks",
   314  		Singular:   "buildpack",
   315  		ShortNames: []string{"bp"},
   316  		Categories: []string{"all"},
   317  	}
   318  	columns := []v1beta1.CustomResourceColumnDefinition{
   319  		{
   320  			Name:        "LABEL",
   321  			Type:        "string",
   322  			Description: "The label of the BuildPack",
   323  			JSONPath:    ".spec.Label",
   324  		},
   325  		{
   326  			Name:        "GIT URL",
   327  			Type:        "string",
   328  			Description: "The Git URL of the BuildPack",
   329  			JSONPath:    ".spec.gitUrl",
   330  		},
   331  		{
   332  			Name:        "Git Ref",
   333  			Type:        "string",
   334  			Description: "The Git REf of the BuildPack",
   335  			JSONPath:    ".spec.gitRef",
   336  		},
   337  	}
   338  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   339  }
   340  
   341  // RegisterAppCRD ensures that the CRD is registered for App
   342  func RegisterAppCRD(apiClient apiextensionsclientset.Interface) error {
   343  	name := "apps." + jenkinsio.GroupName
   344  	names := &v1beta1.CustomResourceDefinitionNames{
   345  		Kind:       "App",
   346  		ListKind:   "AppList",
   347  		Plural:     "apps",
   348  		Singular:   "app",
   349  		ShortNames: []string{"app"},
   350  		Categories: []string{"all"},
   351  	}
   352  	columns := []v1beta1.CustomResourceColumnDefinition{}
   353  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   354  }
   355  
   356  // RegisterPipelineScheduler ensures that the CRD is registered for App
   357  func RegisterPipelineScheduler(apiClient apiextensionsclientset.Interface) error {
   358  	name := "schedulers." + jenkinsio.GroupName
   359  	names := &v1beta1.CustomResourceDefinitionNames{
   360  		Kind:       "Scheduler",
   361  		ListKind:   "SchedulerList",
   362  		Plural:     "schedulers",
   363  		Singular:   "scheduler",
   364  		ShortNames: []string{"scheduler"},
   365  		Categories: []string{"all"},
   366  	}
   367  	columns := []v1beta1.CustomResourceColumnDefinition{}
   368  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   369  }
   370  
   371  // RegisterSourceRepositoryGroup ensures that the CRD is registered for App
   372  func RegisterSourceRepositoryGroup(apiClient apiextensionsclientset.Interface) error {
   373  	name := "sourcerepositorygroups." + jenkinsio.GroupName
   374  	names := &v1beta1.CustomResourceDefinitionNames{
   375  		Kind:       "SourceRepositoryGroup",
   376  		ListKind:   "SourceRepositoryGroupList",
   377  		Plural:     "sourcerepositorygroups",
   378  		Singular:   "sourcerepositorygroup",
   379  		ShortNames: []string{"srg"},
   380  		Categories: []string{"all"},
   381  	}
   382  	columns := []v1beta1.CustomResourceColumnDefinition{
   383  		{
   384  			Name:        "Scheduler",
   385  			Type:        "string",
   386  			Description: "The pipeline scheduler used by the source repository group",
   387  			JSONPath:    ".spec.scheduler.name",
   388  		},
   389  	}
   390  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   391  }
   392  
   393  // RegisterSourceRepositoryCRD ensures that the CRD is registered for Applications
   394  func RegisterSourceRepositoryCRD(apiClient apiextensionsclientset.Interface) error {
   395  	name := "sourcerepositories." + jenkinsio.GroupName
   396  	names := &v1beta1.CustomResourceDefinitionNames{
   397  		Kind:       "SourceRepository",
   398  		ListKind:   "SourceRepositoryList",
   399  		Plural:     "sourcerepositories",
   400  		Singular:   "sourcerepository",
   401  		ShortNames: []string{"sourcerepo", "srcrepo", "sr"},
   402  		Categories: []string{"all"},
   403  	}
   404  	columns := []v1beta1.CustomResourceColumnDefinition{
   405  		{
   406  			Name:        "URL",
   407  			Type:        "string",
   408  			Description: "The URL of the git repository",
   409  			JSONPath:    ".spec.url",
   410  		},
   411  		{
   412  			Name:        "Description",
   413  			Type:        "string",
   414  			Description: "A description of the source code repository - non-functional user-data",
   415  			JSONPath:    ".spec.description",
   416  		},
   417  	}
   418  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   419  }
   420  
   421  // RegisterPluginCRD ensures that the CRD is registered for Plugin
   422  func RegisterPluginCRD(apiClient apiextensionsclientset.Interface) error {
   423  	name := "plugins." + jenkinsio.GroupName
   424  	names := &v1beta1.CustomResourceDefinitionNames{
   425  		Kind:       "Plugin",
   426  		ListKind:   "PluginList",
   427  		Plural:     "plugins",
   428  		Singular:   "plugin",
   429  		Categories: []string{"all"},
   430  	}
   431  	columns := []v1beta1.CustomResourceColumnDefinition{
   432  		{
   433  			Name:        "Name",
   434  			Type:        "string",
   435  			Description: "The name of the plugin",
   436  			JSONPath:    ".spec.name",
   437  		},
   438  		{
   439  			Name:        "Description",
   440  			Type:        "string",
   441  			Description: "A description of the plugin",
   442  			JSONPath:    ".spec.description",
   443  		},
   444  	}
   445  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   446  }
   447  
   448  // RegisterCommitStatusCRD ensures that the CRD is registered for CommitStatus
   449  func RegisterCommitStatusCRD(apiClient apiextensionsclientset.Interface) error {
   450  	name := "commitstatuses." + jenkinsio.GroupName
   451  	names := &v1beta1.CustomResourceDefinitionNames{
   452  		Kind:       "CommitStatus",
   453  		ListKind:   "CommitStatusList",
   454  		Plural:     "commitstatuses",
   455  		Singular:   "commitstatus",
   456  		ShortNames: []string{"commitstatus"},
   457  		Categories: []string{"all"},
   458  	}
   459  	columns := []v1beta1.CustomResourceColumnDefinition{}
   460  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   461  }
   462  
   463  // RegisterReleaseCRD ensures that the CRD is registered for Release
   464  func RegisterReleaseCRD(apiClient apiextensionsclientset.Interface) error {
   465  	name := "releases." + jenkinsio.GroupName
   466  	names := &v1beta1.CustomResourceDefinitionNames{
   467  		Kind:       "Release",
   468  		ListKind:   "ReleaseList",
   469  		Plural:     "releases",
   470  		Singular:   "release",
   471  		ShortNames: []string{"rel"},
   472  		Categories: []string{"all"},
   473  	}
   474  	columns := []v1beta1.CustomResourceColumnDefinition{
   475  		{
   476  			Name:        "Name",
   477  			Type:        "string",
   478  			Description: "The name of the Release",
   479  			JSONPath:    ".spec.name",
   480  		},
   481  		{
   482  			Name:        "Version",
   483  			Type:        "string",
   484  			Description: "The version number of the Release",
   485  			JSONPath:    ".spec.version",
   486  		},
   487  		{
   488  			Name:        "Git URL",
   489  			Type:        "string",
   490  			Description: "The URL of the Git repository",
   491  			JSONPath:    ".spec.gitHttpUrl",
   492  		},
   493  	}
   494  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   495  }
   496  
   497  // RegisterUserCRD ensures that the CRD is registered for User
   498  func RegisterUserCRD(apiClient apiextensionsclientset.Interface) error {
   499  	name := "users." + jenkinsio.GroupName
   500  	names := &v1beta1.CustomResourceDefinitionNames{
   501  		Kind:       "User",
   502  		ListKind:   "UserList",
   503  		Plural:     "users",
   504  		Singular:   "user",
   505  		ShortNames: []string{"usr"},
   506  		Categories: []string{"all"},
   507  	}
   508  	columns := []v1beta1.CustomResourceColumnDefinition{
   509  		{
   510  			Name:        "Name",
   511  			Type:        "string",
   512  			Description: "The name of the user",
   513  			JSONPath:    ".spec.name",
   514  		},
   515  		{
   516  			Name:        "Email",
   517  			Type:        "string",
   518  			Description: "The email address of the user",
   519  			JSONPath:    ".spec.email",
   520  		},
   521  	}
   522  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   523  }
   524  
   525  // RegisterTeamCRD ensures that the CRD is registered for Team
   526  func RegisterTeamCRD(apiClient apiextensionsclientset.Interface) error {
   527  	name := "teams." + jenkinsio.GroupName
   528  	names := &v1beta1.CustomResourceDefinitionNames{
   529  		Kind:       "Team",
   530  		ListKind:   "TeamList",
   531  		Plural:     "teams",
   532  		Singular:   "team",
   533  		ShortNames: []string{"tm"},
   534  		Categories: []string{"all"},
   535  	}
   536  	columns := []v1beta1.CustomResourceColumnDefinition{
   537  		{
   538  			Name:        "Kind",
   539  			Type:        "string",
   540  			Description: "The kind of Team",
   541  			JSONPath:    ".spec.kind",
   542  		},
   543  		{
   544  			Name:        "Status",
   545  			Type:        "string",
   546  			Description: "The provision status of the Team",
   547  			JSONPath:    ".status.provisionStatus",
   548  		},
   549  	}
   550  
   551  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   552  }
   553  
   554  // RegisterWorkflowCRD ensures that the CRD is registered for Environments
   555  func RegisterWorkflowCRD(apiClient apiextensionsclientset.Interface) error {
   556  	name := "workflows." + jenkinsio.GroupName
   557  	names := &v1beta1.CustomResourceDefinitionNames{
   558  		Kind:       "Workflow",
   559  		ListKind:   "WorkflowList",
   560  		Plural:     "workflows",
   561  		Singular:   "workflow",
   562  		ShortNames: []string{"flow"},
   563  		Categories: []string{"all"},
   564  	}
   565  	columns := []v1beta1.CustomResourceColumnDefinition{}
   566  	return RegisterCRD(apiClient, name, names, columns, jenkinsio.GroupName, jenkinsio.Package, jenkinsio.Version)
   567  }
   568  
   569  // RegisterCRD allows new custom resources to be registered using apiClient under a particular name.
   570  // Various forms of the name are provided using names. In Kubernetes 1.11
   571  // and later a custom display format for kubectl is used, which is specified using columns.
   572  func RegisterCRD(apiClient apiextensionsclientset.Interface, name string,
   573  	names *v1beta1.CustomResourceDefinitionNames, columns []v1beta1.CustomResourceColumnDefinition, groupName string,
   574  	pkg string, version string) error {
   575  	//"github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1.PipelineActivity":
   576  	schemaPath := fmt.Sprintf("%s/%s/%s.%s", pkg, groupName, version, names.Kind)
   577  
   578  	schema, err := getOpenAPISchema(schemaPath)
   579  	if err != nil {
   580  		return errors.Wrapf(err, "error generating OpenAPI Schema for %s", schemaPath)
   581  	}
   582  	crd := &v1beta1.CustomResourceDefinition{
   583  		ObjectMeta: metav1.ObjectMeta{
   584  			Name: name,
   585  		},
   586  		Spec: v1beta1.CustomResourceDefinitionSpec{
   587  			Group:                    groupName,
   588  			Version:                  version,
   589  			Scope:                    v1beta1.NamespaceScoped,
   590  			Names:                    *names,
   591  			AdditionalPrinterColumns: columns,
   592  			Validation: &v1beta1.CustomResourceValidation{
   593  				OpenAPIV3Schema: schema,
   594  			},
   595  		},
   596  	}
   597  
   598  	return register(apiClient, name, crd)
   599  }
   600  
   601  func getOpenAPIDefinitions(name string, ref common.ReferenceCallback) *common.OpenAPIDefinition {
   602  	if def, ok := openapi.GetOpenAPIDefinitions(ref)[name]; ok {
   603  		return &def
   604  	}
   605  	return nil
   606  }
   607  
   608  func getOpenAPISchema(defName string) (*v1beta1.JSONSchemaProps, error) {
   609  	refCallBack := func(path string) spec.Ref {
   610  		ref, err := jsonreference.New(path)
   611  		if err != nil {
   612  			log.Logger().Warnf("Error resolving ref %s %v", path, err)
   613  		}
   614  		return spec.Ref{
   615  			Ref: ref,
   616  		}
   617  	}
   618  	if def := getOpenAPIDefinitions(defName, refCallBack); def != nil {
   619  		// resolve references
   620  		schema, err := FixSchema(def.Schema, refCallBack)
   621  		if err != nil {
   622  			return nil, err
   623  		}
   624  		// Unfortunately the schema is generated into one type, and the validation takes another type.
   625  		// However both define the OpenAPI v3 data structures and are compatible, so we i
   626  		bytes, err := json.Marshal(schema)
   627  		if err != nil {
   628  			return nil, err
   629  		}
   630  		def1 := v1beta1.JSONSchemaProps{}
   631  		err = json.Unmarshal(bytes, &def1)
   632  		if err != nil {
   633  			return nil, err
   634  		}
   635  		return &def1, nil
   636  	}
   637  	return nil, nil
   638  }
   639  
   640  // FixSchema walks the schema and automatically fixes it up to be better supported by Kubernetes.
   641  // Current automatic fixes are:
   642  // * resolving $ref
   643  // * remove unresolved $ref
   644  // * clear additionalProperties (this is unsupported in older kubernetes, when we drop them,
   645  // we can investigate adding support, for now use patternProperties)
   646  //
   647  // as these are all unsupported
   648  func FixSchema(schema spec.Schema, ref common.ReferenceCallback) (spec.Schema, error) {
   649  	if schema.Type.Contains("object") {
   650  		for k, v := range schema.Properties {
   651  			resolved, err := FixSchema(v, ref)
   652  			if err != nil {
   653  				return schema, err
   654  			}
   655  			schema.Properties[k] = resolved
   656  		}
   657  		schema.AdditionalProperties = nil
   658  	} else if schema.Type.Contains("array") {
   659  		if schema.Items.Len() == 1 {
   660  			resolved, err := FixSchema(*schema.Items.Schema, ref)
   661  			if err != nil {
   662  				return schema, err
   663  			}
   664  			schema.Items.Schema = &resolved
   665  		} else {
   666  			result := make([]spec.Schema, 0)
   667  			for _, v := range schema.Items.Schemas {
   668  				resolved, err := FixSchema(v, ref)
   669  				if err != nil {
   670  					return schema, err
   671  				}
   672  				result = append(result, resolved)
   673  			}
   674  			schema.Items.Schemas = result
   675  		}
   676  
   677  	} else if path := schema.Ref.String(); path != "" {
   678  		def := getOpenAPIDefinitions(path, ref)
   679  		if def != nil {
   680  			return FixSchema(def.Schema, ref)
   681  		}
   682  		// return an empty schema if we can't resolve
   683  		return spec.Schema{}, nil
   684  	}
   685  	return schema, nil
   686  }
   687  
   688  func register(apiClient apiextensionsclientset.Interface, name string, crd *v1beta1.CustomResourceDefinition) error {
   689  	crdResources := apiClient.ApiextensionsV1beta1().CustomResourceDefinitions()
   690  
   691  	f := func() error {
   692  		old, err := crdResources.Get(name, metav1.GetOptions{})
   693  		if err == nil {
   694  			if !reflect.DeepEqual(&crd.Spec, old.Spec) {
   695  				old.Spec = crd.Spec
   696  				_, err = crdResources.Update(old)
   697  				if err != nil {
   698  					log.Logger().Infof("Error doing update to %s %v\n%v", old.Name, err, old.Spec)
   699  				}
   700  				return err
   701  			}
   702  			return nil
   703  		}
   704  
   705  		_, err = crdResources.Create(crd)
   706  		if err != nil {
   707  			log.Logger().Infof("Error creating %s: %v", crd.Name, err)
   708  		}
   709  		return err
   710  	}
   711  
   712  	exponentialBackOff := backoff.NewExponentialBackOff()
   713  	timeout := 60 * time.Second
   714  	exponentialBackOff.MaxElapsedTime = timeout
   715  	exponentialBackOff.Reset()
   716  	return backoff.Retry(f, exponentialBackOff)
   717  }