proxy.go 11 KB

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