github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/caasoperator/initializer_test.go (about) 1 // Copyright 2019 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasoperator_test 5 6 import ( 7 "bytes" 8 "os" 9 "path/filepath" 10 "time" 11 12 jujuclock "github.com/juju/clock" 13 "github.com/juju/clock/testclock" 14 "github.com/juju/errors" 15 "github.com/juju/loggo" 16 "github.com/juju/names/v5" 17 jc "github.com/juju/testing/checkers" 18 "go.uber.org/mock/gomock" 19 gc "gopkg.in/check.v1" 20 21 "github.com/juju/juju/caas" 22 "github.com/juju/juju/caas/kubernetes/provider/exec" 23 "github.com/juju/juju/testing" 24 coretesting "github.com/juju/juju/testing" 25 "github.com/juju/juju/worker/caasoperator" 26 "github.com/juju/juju/worker/caasoperator/mocks" 27 ) 28 29 type UnitInitializerSuite struct { 30 coretesting.BaseSuite 31 } 32 33 var _ = gc.Suite(&UnitInitializerSuite{}) 34 35 func (s *UnitInitializerSuite) SetUpTest(c *gc.C) { 36 s.BaseSuite.SetUpTest(c) 37 } 38 39 func (s *UnitInitializerSuite) TestInitialize(c *gc.C) { 40 ctrl := gomock.NewController(c) 41 defer ctrl.Finish() 42 43 mockExecClient := mocks.NewMockExecutor(ctrl) 44 45 params := caasoperator.InitializeUnitParams{ 46 ReTrier: func(f func() error, _ func(error) bool, _ caasoperator.Logger, _ jujuclock.Clock, _ <-chan struct{}) error { 47 return f() 48 }, 49 UnitTag: names.NewUnitTag("gitlab/0"), 50 Logger: loggo.GetLogger("test"), 51 Paths: caasoperator.Paths{ 52 State: caasoperator.StatePaths{ 53 CharmDir: "dir/charm", 54 }, 55 }, 56 ExecClient: mockExecClient, 57 OperatorInfo: caas.OperatorInfo{ 58 CACert: "ca-cert", 59 }, 60 ProviderID: "gitlab-ffff", 61 TempDir: func(dir string, prefix string) (string, error) { 62 return filepath.Join(dir, prefix+"-random"), nil 63 }, 64 WriteFile: func(path string, data []byte, perm os.FileMode) error { 65 return nil 66 }, 67 } 68 69 gomock.InOrder( 70 mockExecClient.EXPECT().Exec(exec.ExecParams{ 71 Commands: []string{"mkdir", "-p", filepath.Join(os.TempDir(), "unit-gitlab-0-random")}, 72 PodName: "gitlab-ffff", 73 ContainerName: "juju-pod-init", 74 Stdout: &bytes.Buffer{}, 75 Stderr: &bytes.Buffer{}, 76 }, gomock.Any()).Return(nil), 77 mockExecClient.EXPECT().Copy(exec.CopyParams{ 78 Src: exec.FileResource{ 79 Path: "dir/charm", 80 }, 81 Dest: exec.FileResource{ 82 Path: filepath.Join(os.TempDir(), "unit-gitlab-0-random"), 83 PodName: "gitlab-ffff", 84 ContainerName: "juju-pod-init", 85 }, 86 }, gomock.Any()).Return(nil), 87 mockExecClient.EXPECT().Copy(exec.CopyParams{ 88 Src: exec.FileResource{ 89 Path: filepath.Join(os.TempDir(), "unit-gitlab-0-random/ca.crt"), 90 }, 91 Dest: exec.FileResource{ 92 Path: filepath.Join(os.TempDir(), "unit-gitlab-0-random/ca.crt"), 93 PodName: "gitlab-ffff", 94 ContainerName: "juju-pod-init", 95 }, 96 }, gomock.Any()).Return(nil), 97 mockExecClient.EXPECT().Copy(exec.CopyParams{ 98 Src: exec.FileResource{ 99 Path: "/var/lib/juju/agents/unit-gitlab-0/operator-client-cache.yaml", 100 }, 101 Dest: exec.FileResource{ 102 Path: filepath.Join(os.TempDir(), "unit-gitlab-0-random/operator-client-cache.yaml"), 103 PodName: "gitlab-ffff", 104 ContainerName: "juju-pod-init", 105 }, 106 }, gomock.Any()).Return(nil), 107 mockExecClient.EXPECT().Exec(exec.ExecParams{ 108 Commands: []string{"/var/lib/juju/tools/jujud", "caas-unit-init", 109 "--unit", "unit-gitlab-0", 110 "--charm-dir", 111 filepath.Join(os.TempDir(), "unit-gitlab-0-random/charm"), 112 "--send", 113 "--operator-file", 114 filepath.Join(os.TempDir(), "unit-gitlab-0-random/operator-client-cache.yaml"), 115 "--operator-ca-cert-file", 116 filepath.Join(os.TempDir(), "unit-gitlab-0-random/ca.crt"), 117 }, 118 WorkingDir: "/var/lib/juju", 119 PodName: "gitlab-ffff", 120 ContainerName: "juju-pod-init", 121 Stdout: &bytes.Buffer{}, 122 Stderr: &bytes.Buffer{}, 123 }, gomock.Any()).Return(nil), 124 ) 125 126 cancel := make(chan struct{}) 127 err := caasoperator.InitializeUnit(params, cancel) 128 c.Assert(err, jc.ErrorIsNil) 129 } 130 131 func (s *UnitInitializerSuite) TestInitializeUnitMissingProviderID(c *gc.C) { 132 ctrl := gomock.NewController(c) 133 defer ctrl.Finish() 134 135 mockExecClient := mocks.NewMockExecutor(ctrl) 136 137 params := caasoperator.InitializeUnitParams{ 138 ReTrier: func(f func() error, _ func(error) bool, _ caasoperator.Logger, _ jujuclock.Clock, _ <-chan struct{}) error { 139 return f() 140 }, 141 UnitTag: names.NewUnitTag("gitlab/0"), 142 Logger: loggo.GetLogger("test"), 143 Paths: caasoperator.Paths{ 144 State: caasoperator.StatePaths{ 145 CharmDir: "dir/charm", 146 }, 147 }, 148 ExecClient: mockExecClient, 149 OperatorInfo: caas.OperatorInfo{ 150 CACert: "ca-cert", 151 }, 152 ProviderID: "", 153 TempDir: func(dir string, prefix string) (string, error) { 154 return filepath.Join(dir, prefix+"-random"), nil 155 }, 156 WriteFile: func(path string, data []byte, perm os.FileMode) error { 157 return nil 158 }, 159 } 160 161 gomock.InOrder() 162 163 cancel := make(chan struct{}) 164 err := caasoperator.InitializeUnit(params, cancel) 165 c.Assert(err, gc.ErrorMatches, "missing ProviderID not valid") 166 } 167 168 func (s *UnitInitializerSuite) TestInitializeContainerMissing(c *gc.C) { 169 ctrl := gomock.NewController(c) 170 defer ctrl.Finish() 171 172 mockExecClient := mocks.NewMockExecutor(ctrl) 173 174 params := caasoperator.InitializeUnitParams{ 175 ReTrier: func(f func() error, _ func(error) bool, _ caasoperator.Logger, _ jujuclock.Clock, _ <-chan struct{}) error { 176 return f() 177 }, 178 UnitTag: names.NewUnitTag("gitlab/0"), 179 Logger: loggo.GetLogger("test"), 180 Paths: caasoperator.Paths{ 181 State: caasoperator.StatePaths{ 182 CharmDir: "dir/charm", 183 }, 184 }, 185 ExecClient: mockExecClient, 186 OperatorInfo: caas.OperatorInfo{ 187 CACert: "ca-cert", 188 }, 189 ProviderID: "gitlab-ffff", 190 TempDir: func(dir string, prefix string) (string, error) { 191 return filepath.Join(dir, prefix+"-random"), nil 192 }, 193 WriteFile: func(path string, data []byte, perm os.FileMode) error { 194 return nil 195 }, 196 } 197 198 gomock.InOrder( 199 mockExecClient.EXPECT().Exec(exec.ExecParams{ 200 Commands: []string{"mkdir", "-p", filepath.Join(os.TempDir(), "unit-gitlab-0-random")}, 201 PodName: "gitlab-ffff", 202 ContainerName: "juju-pod-init", 203 Stdout: &bytes.Buffer{}, 204 Stderr: &bytes.Buffer{}, 205 }, gomock.Any()).Return(nil), 206 mockExecClient.EXPECT().Copy(exec.CopyParams{ 207 Src: exec.FileResource{ 208 Path: "dir/charm", 209 }, 210 Dest: exec.FileResource{ 211 Path: filepath.Join(os.TempDir(), "unit-gitlab-0-random"), 212 PodName: "gitlab-ffff", 213 ContainerName: "juju-pod-init", 214 }, 215 }, gomock.Any()).Return(errors.NotFoundf("container")), 216 ) 217 218 cancel := make(chan struct{}) 219 err := caasoperator.InitializeUnit(params, cancel) 220 c.Assert(err, gc.ErrorMatches, "container not found") 221 } 222 223 func (s *UnitInitializerSuite) TestInitializePodNotFound(c *gc.C) { 224 ctrl := gomock.NewController(c) 225 defer ctrl.Finish() 226 227 mockExecClient := mocks.NewMockExecutor(ctrl) 228 229 params := caasoperator.InitializeUnitParams{ 230 ReTrier: func(f func() error, _ func(error) bool, _ caasoperator.Logger, _ jujuclock.Clock, _ <-chan struct{}) error { 231 return f() 232 }, 233 UnitTag: names.NewUnitTag("gitlab/0"), 234 Logger: loggo.GetLogger("test"), 235 Paths: caasoperator.Paths{ 236 State: caasoperator.StatePaths{ 237 CharmDir: "dir/charm", 238 }, 239 }, 240 ExecClient: mockExecClient, 241 OperatorInfo: caas.OperatorInfo{ 242 CACert: "ca-cert", 243 }, 244 ProviderID: "gitlab-ffff", 245 TempDir: func(dir string, prefix string) (string, error) { 246 return filepath.Join(dir, prefix+"-random"), nil 247 }, 248 WriteFile: func(path string, data []byte, perm os.FileMode) error { 249 return nil 250 }, 251 } 252 253 gomock.InOrder( 254 mockExecClient.EXPECT().Exec(exec.ExecParams{ 255 Commands: []string{"mkdir", "-p", filepath.Join(os.TempDir(), "unit-gitlab-0-random")}, 256 PodName: "gitlab-ffff", 257 ContainerName: "juju-pod-init", 258 Stdout: &bytes.Buffer{}, 259 Stderr: &bytes.Buffer{}, 260 }, gomock.Any()).Return(nil), 261 mockExecClient.EXPECT().Copy(exec.CopyParams{ 262 Src: exec.FileResource{ 263 Path: "dir/charm", 264 }, 265 Dest: exec.FileResource{ 266 Path: filepath.Join(os.TempDir(), "unit-gitlab-0-random"), 267 PodName: "gitlab-ffff", 268 ContainerName: "juju-pod-init", 269 }, 270 }, gomock.Any()).Return(errors.NotFoundf("container")), 271 ) 272 273 cancel := make(chan struct{}) 274 err := caasoperator.InitializeUnit(params, cancel) 275 c.Assert(err, gc.ErrorMatches, "container not found") 276 } 277 278 func (s *UnitInitializerSuite) TestRunnerWithRetry(c *gc.C) { 279 cancel := make(chan struct{}) 280 clk := testclock.NewClock(time.Time{}) 281 called := 0 282 execRequest := func() error { 283 called++ 284 if called < 3 { 285 return exec.NewExecRetryableError(errors.New("fake testing 137")) 286 } 287 return nil 288 } 289 290 errChan := make(chan error) 291 go func() { 292 errChan <- caasoperator.RunnerWithRetry(execRequest, func(err error) bool { 293 return err != nil && !exec.IsExecRetryableError(err) 294 }, loggo.GetLogger("test"), clk, cancel) 295 }() 296 err := clk.WaitAdvance(2*time.Second, testing.ShortWait, 1) 297 c.Assert(err, jc.ErrorIsNil) 298 err = clk.WaitAdvance(2*time.Second, testing.ShortWait, 1) 299 c.Assert(err, jc.ErrorIsNil) 300 301 select { 302 case err := <-errChan: 303 c.Assert(err, jc.ErrorIsNil) 304 c.Assert(called, gc.DeepEquals, 3) 305 case <-time.After(testing.LongWait): 306 c.Fatalf("timed out waiting for RunnerWithRetry return") 307 } 308 }