1 package kclient
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "time"
8
9 projectv1 "github.com/openshift/api/project/v1"
10 corev1 "k8s.io/api/core/v1"
11 kerrors "k8s.io/apimachinery/pkg/api/errors"
12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13 "k8s.io/apimachinery/pkg/fields"
14 "k8s.io/apimachinery/pkg/watch"
15 "k8s.io/klog"
16 )
17
18 const (
19
20 waitForProjectDeletionTimeOut = 3 * time.Minute
21 )
22
23
24
25 func (c *Client) GetProject(projectName string) (*projectv1.Project, error) {
26 prj, err := c.projectClient.Projects().Get(context.TODO(), projectName, metav1.GetOptions{})
27 if err != nil {
28 istatus, ok := err.(kerrors.APIStatus)
29 if ok {
30 status := istatus.Status()
31 if status.Reason == metav1.StatusReasonNotFound || status.Reason == metav1.StatusReasonForbidden {
32 return nil, nil
33 }
34 } else {
35 return nil, err
36 }
37
38 }
39 return prj, err
40
41 }
42
43
44 func (c *Client) ListProjects() (*projectv1.ProjectList, error) {
45 return c.projectClient.Projects().List(context.TODO(), metav1.ListOptions{})
46 }
47
48
49 func (c *Client) ListProjectNames() ([]string, error) {
50 projects, err := c.ListProjects()
51 if err != nil {
52 return nil, err
53 }
54
55 var projectNames []string
56 for _, p := range projects.Items {
57 projectNames = append(projectNames, p.Name)
58 }
59 return projectNames, nil
60 }
61
62
63
64
65
66
67
68
69
70
71
72 func (c *Client) DeleteProject(name string, wait bool) error {
73
74
75 var watcher watch.Interface
76 var err error
77
78
79 if wait {
80 watcher, err = c.projectClient.Projects().Watch(context.TODO(), metav1.ListOptions{
81 FieldSelector: fields.Set{"metadata.name": name}.AsSelector().String(),
82 })
83 if err != nil {
84 return fmt.Errorf("unable to watch project: %w", err)
85 }
86 defer watcher.Stop()
87 }
88
89
90 err = c.projectClient.Projects().Delete(context.TODO(), name, metav1.DeleteOptions{})
91 if err != nil {
92 return fmt.Errorf("unable to delete project: %w", err)
93 }
94
95
96
97 if watcher != nil {
98
99
100
101 projectChannel := make(chan *projectv1.Project)
102 watchErrorChannel := make(chan error)
103
104
105 go func() {
106
107 for {
108
109
110 val, ok := <-watcher.ResultChan()
111 if !ok {
112
113 watchErrorChannel <- fmt.Errorf("watch channel was closed unexpectedly: %+v", val)
114 break
115 }
116
117
118 if projectStatus, ok := val.Object.(*projectv1.Project); ok {
119
120 klog.V(3).Infof("Status of delete of project %s is '%s'", name, projectStatus.Status.Phase)
121
122 switch projectStatus.Status.Phase {
123
124 case "":
125 if val.Type == watch.Deleted {
126 projectChannel <- projectStatus
127 break
128 }
129 if val.Type == watch.Error {
130 watchErrorChannel <- fmt.Errorf("failed watching the deletion of project %s", name)
131 break
132 }
133 }
134
135 } else {
136 watchErrorChannel <- errors.New("unable to convert event object to Project")
137 break
138 }
139
140 }
141 close(projectChannel)
142 close(watchErrorChannel)
143 }()
144
145 select {
146 case val := <-projectChannel:
147 klog.V(3).Infof("Deletion information for project: %+v", val)
148 return nil
149 case err := <-watchErrorChannel:
150 return err
151 case <-time.After(waitForProjectDeletionTimeOut):
152 return fmt.Errorf("waited %s but couldn't delete project %s in time", waitForProjectDeletionTimeOut, name)
153 }
154
155 }
156
157
158 return nil
159 }
160
161
162 func (c *Client) CreateNewProject(projectName string, wait bool) error {
163
164
165
166 var watcher watch.Interface
167 var err error
168 if wait {
169 watcher, err = c.projectClient.Projects().Watch(context.TODO(), metav1.ListOptions{
170 FieldSelector: fields.Set{"metadata.name": projectName}.AsSelector().String(),
171 })
172 if err != nil {
173 return fmt.Errorf("unable to watch new project %s creation: %w", projectName, err)
174 }
175 defer watcher.Stop()
176 }
177
178 projectRequest := &projectv1.ProjectRequest{
179 ObjectMeta: metav1.ObjectMeta{
180 Name: projectName,
181 },
182 }
183 _, err = c.projectClient.ProjectRequests().Create(context.TODO(), projectRequest, metav1.CreateOptions{FieldManager: FieldManager})
184 if err != nil {
185 return fmt.Errorf("unable to create new project %s: %w", projectName, err)
186 }
187
188 if watcher != nil {
189 for {
190 val, ok := <-watcher.ResultChan()
191 if !ok {
192 break
193 }
194 if prj, ok := val.Object.(*projectv1.Project); ok {
195 klog.V(3).Infof("Status of creation of project %s is %s", prj.Name, prj.Status.Phase)
196 switch prj.Status.Phase {
197
198 case corev1.NamespaceActive:
199 if val.Type == watch.Added {
200 klog.V(3).Infof("Project %s now exists", prj.Name)
201 return nil
202 }
203 if val.Type == watch.Error {
204 return fmt.Errorf("failed watching the deletion of project %s", prj.Name)
205 }
206 }
207 }
208 }
209 }
210
211 return nil
212 }
213
214
215 func (c *Client) IsProjectSupported() (bool, error) {
216 return c.IsResourceSupported("project.openshift.io", "v1", "projects")
217 }
218
219
220 func (c *Client) GetCurrentProjectName() string {
221 return c.Namespace
222 }
223
View as plain text