proxy.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. Copyright 2020 Docker Compose CLI 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 api
  14. import (
  15. "context"
  16. "github.com/compose-spec/compose-go/types"
  17. )
  18. var _ Service = &ServiceProxy{}
  19. // ServiceProxy implements Service by delegating to implementation functions. This allows lazy init and per-method overrides
  20. type ServiceProxy struct {
  21. BuildFn func(ctx context.Context, project *types.Project, options BuildOptions) error
  22. PushFn func(ctx context.Context, project *types.Project, options PushOptions) error
  23. PullFn func(ctx context.Context, project *types.Project, opts PullOptions) error
  24. CreateFn func(ctx context.Context, project *types.Project, opts CreateOptions) error
  25. StartFn func(ctx context.Context, projectName string, options StartOptions) error
  26. RestartFn func(ctx context.Context, projectName string, options RestartOptions) error
  27. StopFn func(ctx context.Context, projectName string, options StopOptions) error
  28. UpFn func(ctx context.Context, project *types.Project, options UpOptions) error
  29. DownFn func(ctx context.Context, projectName string, options DownOptions) error
  30. LogsFn func(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error
  31. PsFn func(ctx context.Context, projectName string, options PsOptions) ([]ContainerSummary, error)
  32. ListFn func(ctx context.Context, options ListOptions) ([]Stack, error)
  33. ConfigFn func(ctx context.Context, project *types.Project, options ConfigOptions) ([]byte, error)
  34. KillFn func(ctx context.Context, project string, options KillOptions) error
  35. RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
  36. RemoveFn func(ctx context.Context, project string, options RemoveOptions) error
  37. ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error)
  38. CopyFn func(ctx context.Context, project string, options CopyOptions) error
  39. PauseFn func(ctx context.Context, project string, options PauseOptions) error
  40. UnPauseFn func(ctx context.Context, project string, options PauseOptions) error
  41. TopFn func(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error)
  42. EventsFn func(ctx context.Context, project string, options EventsOptions) error
  43. PortFn func(ctx context.Context, project string, service string, port uint16, options PortOptions) (string, int, error)
  44. ImagesFn func(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
  45. WatchFn func(ctx context.Context, project *types.Project, services []string, options WatchOptions) error
  46. MaxConcurrencyFn func(parallel int)
  47. DryRunModeFn func(ctx context.Context, dryRun bool) (context.Context, error)
  48. VizFn func(ctx context.Context, project *types.Project, options VizOptions) (string, error)
  49. WaitFn func(ctx context.Context, projectName string, options WaitOptions) (int64, error)
  50. PublishFn func(ctx context.Context, project *types.Project, repository string) error
  51. interceptors []Interceptor
  52. }
  53. // NewServiceProxy produces a ServiceProxy
  54. func NewServiceProxy() *ServiceProxy {
  55. return &ServiceProxy{}
  56. }
  57. // Interceptor allow to customize the compose types.Project before the actual Service method is executed
  58. type Interceptor func(ctx context.Context, project *types.Project)
  59. // WithService configure proxy to use specified Service as delegate
  60. func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
  61. s.BuildFn = service.Build
  62. s.PushFn = service.Push
  63. s.PullFn = service.Pull
  64. s.CreateFn = service.Create
  65. s.StartFn = service.Start
  66. s.RestartFn = service.Restart
  67. s.StopFn = service.Stop
  68. s.UpFn = service.Up
  69. s.DownFn = service.Down
  70. s.LogsFn = service.Logs
  71. s.PsFn = service.Ps
  72. s.ListFn = service.List
  73. s.ConfigFn = service.Config
  74. s.KillFn = service.Kill
  75. s.RunOneOffContainerFn = service.RunOneOffContainer
  76. s.RemoveFn = service.Remove
  77. s.ExecFn = service.Exec
  78. s.CopyFn = service.Copy
  79. s.PauseFn = service.Pause
  80. s.UnPauseFn = service.UnPause
  81. s.TopFn = service.Top
  82. s.EventsFn = service.Events
  83. s.PortFn = service.Port
  84. s.PublishFn = service.Publish
  85. s.ImagesFn = service.Images
  86. s.WatchFn = service.Watch
  87. s.MaxConcurrencyFn = service.MaxConcurrency
  88. s.DryRunModeFn = service.DryRunMode
  89. s.VizFn = service.Viz
  90. s.WaitFn = service.Wait
  91. return s
  92. }
  93. // WithInterceptor configures Interceptor to be applied to Service method execution
  94. func (s *ServiceProxy) WithInterceptor(interceptors ...Interceptor) *ServiceProxy {
  95. s.interceptors = append(s.interceptors, interceptors...)
  96. return s
  97. }
  98. // Build implements Service interface
  99. func (s *ServiceProxy) Build(ctx context.Context, project *types.Project, options BuildOptions) error {
  100. if s.BuildFn == nil {
  101. return ErrNotImplemented
  102. }
  103. for _, i := range s.interceptors {
  104. i(ctx, project)
  105. }
  106. return s.BuildFn(ctx, project, options)
  107. }
  108. // Push implements Service interface
  109. func (s *ServiceProxy) Push(ctx context.Context, project *types.Project, options PushOptions) error {
  110. if s.PushFn == nil {
  111. return ErrNotImplemented
  112. }
  113. for _, i := range s.interceptors {
  114. i(ctx, project)
  115. }
  116. return s.PushFn(ctx, project, options)
  117. }
  118. // Pull implements Service interface
  119. func (s *ServiceProxy) Pull(ctx context.Context, project *types.Project, options PullOptions) error {
  120. if s.PullFn == nil {
  121. return ErrNotImplemented
  122. }
  123. for _, i := range s.interceptors {
  124. i(ctx, project)
  125. }
  126. return s.PullFn(ctx, project, options)
  127. }
  128. // Create implements Service interface
  129. func (s *ServiceProxy) Create(ctx context.Context, project *types.Project, options CreateOptions) error {
  130. if s.CreateFn == nil {
  131. return ErrNotImplemented
  132. }
  133. for _, i := range s.interceptors {
  134. i(ctx, project)
  135. }
  136. return s.CreateFn(ctx, project, options)
  137. }
  138. // Start implements Service interface
  139. func (s *ServiceProxy) Start(ctx context.Context, projectName string, options StartOptions) error {
  140. if s.StartFn == nil {
  141. return ErrNotImplemented
  142. }
  143. return s.StartFn(ctx, projectName, options)
  144. }
  145. // Restart implements Service interface
  146. func (s *ServiceProxy) Restart(ctx context.Context, projectName string, options RestartOptions) error {
  147. if s.RestartFn == nil {
  148. return ErrNotImplemented
  149. }
  150. return s.RestartFn(ctx, projectName, options)
  151. }
  152. // Stop implements Service interface
  153. func (s *ServiceProxy) Stop(ctx context.Context, projectName string, options StopOptions) error {
  154. if s.StopFn == nil {
  155. return ErrNotImplemented
  156. }
  157. return s.StopFn(ctx, projectName, options)
  158. }
  159. // Up implements Service interface
  160. func (s *ServiceProxy) Up(ctx context.Context, project *types.Project, options UpOptions) error {
  161. if s.UpFn == nil {
  162. return ErrNotImplemented
  163. }
  164. for _, i := range s.interceptors {
  165. i(ctx, project)
  166. }
  167. return s.UpFn(ctx, project, options)
  168. }
  169. // Down implements Service interface
  170. func (s *ServiceProxy) Down(ctx context.Context, project string, options DownOptions) error {
  171. if s.DownFn == nil {
  172. return ErrNotImplemented
  173. }
  174. return s.DownFn(ctx, project, options)
  175. }
  176. // Logs implements Service interface
  177. func (s *ServiceProxy) Logs(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error {
  178. if s.LogsFn == nil {
  179. return ErrNotImplemented
  180. }
  181. return s.LogsFn(ctx, projectName, consumer, options)
  182. }
  183. // Ps implements Service interface
  184. func (s *ServiceProxy) Ps(ctx context.Context, project string, options PsOptions) ([]ContainerSummary, error) {
  185. if s.PsFn == nil {
  186. return nil, ErrNotImplemented
  187. }
  188. return s.PsFn(ctx, project, options)
  189. }
  190. // List implements Service interface
  191. func (s *ServiceProxy) List(ctx context.Context, options ListOptions) ([]Stack, error) {
  192. if s.ListFn == nil {
  193. return nil, ErrNotImplemented
  194. }
  195. return s.ListFn(ctx, options)
  196. }
  197. // Config implements Service interface
  198. func (s *ServiceProxy) Config(ctx context.Context, project *types.Project, options ConfigOptions) ([]byte, error) {
  199. if s.ConfigFn == nil {
  200. return nil, ErrNotImplemented
  201. }
  202. for _, i := range s.interceptors {
  203. i(ctx, project)
  204. }
  205. return s.ConfigFn(ctx, project, options)
  206. }
  207. // Kill implements Service interface
  208. func (s *ServiceProxy) Kill(ctx context.Context, projectName string, options KillOptions) error {
  209. if s.KillFn == nil {
  210. return ErrNotImplemented
  211. }
  212. return s.KillFn(ctx, projectName, options)
  213. }
  214. // RunOneOffContainer implements Service interface
  215. func (s *ServiceProxy) RunOneOffContainer(ctx context.Context, project *types.Project, options RunOptions) (int, error) {
  216. if s.RunOneOffContainerFn == nil {
  217. return 0, ErrNotImplemented
  218. }
  219. for _, i := range s.interceptors {
  220. i(ctx, project)
  221. }
  222. return s.RunOneOffContainerFn(ctx, project, options)
  223. }
  224. // Remove implements Service interface
  225. func (s *ServiceProxy) Remove(ctx context.Context, projectName string, options RemoveOptions) error {
  226. if s.RemoveFn == nil {
  227. return ErrNotImplemented
  228. }
  229. return s.RemoveFn(ctx, projectName, options)
  230. }
  231. // Exec implements Service interface
  232. func (s *ServiceProxy) Exec(ctx context.Context, projectName string, options RunOptions) (int, error) {
  233. if s.ExecFn == nil {
  234. return 0, ErrNotImplemented
  235. }
  236. return s.ExecFn(ctx, projectName, options)
  237. }
  238. // Copy implements Service interface
  239. func (s *ServiceProxy) Copy(ctx context.Context, projectName string, options CopyOptions) error {
  240. if s.CopyFn == nil {
  241. return ErrNotImplemented
  242. }
  243. return s.CopyFn(ctx, projectName, options)
  244. }
  245. // Pause implements Service interface
  246. func (s *ServiceProxy) Pause(ctx context.Context, projectName string, options PauseOptions) error {
  247. if s.PauseFn == nil {
  248. return ErrNotImplemented
  249. }
  250. return s.PauseFn(ctx, projectName, options)
  251. }
  252. // UnPause implements Service interface
  253. func (s *ServiceProxy) UnPause(ctx context.Context, projectName string, options PauseOptions) error {
  254. if s.UnPauseFn == nil {
  255. return ErrNotImplemented
  256. }
  257. return s.UnPauseFn(ctx, projectName, options)
  258. }
  259. // Top implements Service interface
  260. func (s *ServiceProxy) Top(ctx context.Context, project string, services []string) ([]ContainerProcSummary, error) {
  261. if s.TopFn == nil {
  262. return nil, ErrNotImplemented
  263. }
  264. return s.TopFn(ctx, project, services)
  265. }
  266. // Events implements Service interface
  267. func (s *ServiceProxy) Events(ctx context.Context, projectName string, options EventsOptions) error {
  268. if s.EventsFn == nil {
  269. return ErrNotImplemented
  270. }
  271. return s.EventsFn(ctx, projectName, options)
  272. }
  273. // Port implements Service interface
  274. func (s *ServiceProxy) Port(ctx context.Context, projectName string, service string, port uint16, options PortOptions) (string, int, error) {
  275. if s.PortFn == nil {
  276. return "", 0, ErrNotImplemented
  277. }
  278. return s.PortFn(ctx, projectName, service, port, options)
  279. }
  280. func (s *ServiceProxy) Publish(ctx context.Context, project *types.Project, repository string) error {
  281. return s.PublishFn(ctx, project, repository)
  282. }
  283. // Images implements Service interface
  284. func (s *ServiceProxy) Images(ctx context.Context, project string, options ImagesOptions) ([]ImageSummary, error) {
  285. if s.ImagesFn == nil {
  286. return nil, ErrNotImplemented
  287. }
  288. return s.ImagesFn(ctx, project, options)
  289. }
  290. // Watch implements Service interface
  291. func (s *ServiceProxy) Watch(ctx context.Context, project *types.Project, services []string, options WatchOptions) error {
  292. if s.WatchFn == nil {
  293. return ErrNotImplemented
  294. }
  295. return s.WatchFn(ctx, project, services, options)
  296. }
  297. // Viz implements Service interface
  298. func (s *ServiceProxy) Viz(ctx context.Context, project *types.Project, options VizOptions) (string, error) {
  299. if s.VizFn == nil {
  300. return "", ErrNotImplemented
  301. }
  302. return s.VizFn(ctx, project, options)
  303. }
  304. // Wait implements Service interface
  305. func (s *ServiceProxy) Wait(ctx context.Context, projectName string, options WaitOptions) (int64, error) {
  306. if s.WaitFn == nil {
  307. return 0, ErrNotImplemented
  308. }
  309. return s.WaitFn(ctx, projectName, options)
  310. }
  311. func (s *ServiceProxy) MaxConcurrency(i int) {
  312. s.MaxConcurrencyFn(i)
  313. }
  314. func (s *ServiceProxy) DryRunMode(ctx context.Context, dryRun bool) (context.Context, error) {
  315. return s.DryRunModeFn(ctx, dryRun)
  316. }