-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WiP] Refactor common Kontena classes in monorepo form #2559
Conversation
|
||
CMD ["/app/bin/kontena-agent"] | ||
WORKDIR /opt/kontena/agent | ||
CMD bundle exec /opt/kontena/agent/bin/kontena-agent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using bundle exec
to add the /opt/kontena/common/lib
to the $LOAD_PATH
... not sure if the best way to do it, but probably the fastest.
kontena gem build /opt/kontena/common/kontena-common.gemspec && gem install kontena-common-*.gem
?- ???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we keep Dockerfile under agent
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we could, but I think it's better to have the Dockerfile
be in the actual docker build context dir... That way it's apparent that you have to build it with kontena $ docker build -t kontena/agent -f Dockerfile.agent .
. If it is just agent/Dockerfile
, then the obvious thing of kontena/agent $ docker build -t kontena/agent .
will fail.
|
||
Gem::Specification.new do |s| | ||
s.name = 'kontena-common' | ||
s.version = '1.4.0.dev' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO to read this from ../VERSION
@@ -0,0 +1,3 @@ | |||
module Kontena | |||
require_relative './kontena/logging' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This already exists as lib/kontena/logging.rb
and can be required by require 'kontena/logging'
. I don't think this kontena-logging.rb
adds much value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is there to define the Kontena
module... just require 'kontena/logging'
will fail if it's the first thing being required, and nothing else has yet done module Kontena
.
Could change these to just use require 'kontena/logging'
, but then each class would have to be like
module Kontena
module Foo
class Bar
# actual code with too much indentation
Not so much a problem for the basic logging thing, but annoying enough already for the Kontena::Websocket::Client
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK besides ruby gems don't really allow for requiring specific sub-parts of gems in general, you generally have a single top-level require per gem.
But I don't want to make kontena-common.rb
require every possible thing either... so several separate top-level requires like this instead?
@jakolehm @jnummelin @kke I'd like some initial feedback on the design before I go any further, to avoid wasted effort. Does the concept of a common load path for shared code between the different server/agent/cli/test components in the same repo make sense? Plan is to start with the The intention isn't to be a replacement for creating separate gems, but a pragmatic alternative to copy-pasting code between the different components... if there's some function that would be useful in both the server and cli, the threshold for moving it into some external gem is pretty high, and just copy-pasting it is easier. This There's some issues with a single
As regards shared components like the |
There are up and downsides. Pros:
Cons:
Some observations:
I think a pattern for something like module KontenaUtil
extend SingleForwardable
autoload :WaitUntil, 'kontena_util/wait_until'
def_delegator :WaitUntil, :wait_until
end
module KontenaUtil
module WaitUntil
module_function
def wait_until(*opts)
...
end
end
end class Foo
include KontenaUtil::WaitUntil
def execute
wait_until(:xyz) do
..
end
end
class Bar
def self.execute
KontenaUtil.wait_until(:xyz) do
..
end
end
end
> Foo.new.wait_until => private method wait_until called
> Foo.new.public_methods.grep(/wait_until/) => nothing found
> Foo.new.execute => ok
> Bar.execute => ok Another option is And a note about module/class nesting: module A
module B
def self.foo
"foo"
end
end
end
module A::C
def self.bar
B.foo
end
end
module A
module D
def self.baz
B.foo
end
end
end
A::D.baz
=> "foo"
A::B.bar
=> uninitialized constant A::B::C (NameError)
Did you mean? A::C If you use explicit nesting, you can do something like:
If you don't, you can't:
Why this happens, I have no idea. Anyway, explicit nesting is often better anyway as you don't hit those "parent module namespace does not exist yet if you require 'foofoo/foofoo'" situations. |
Thanks for the response
Yeah... this is a problem with the agent, because it has all of its code under
Yeah, the Kontena::Wait.wait_until { ... } And then perhaps a separate mixin-module that just provides identical instance methods: class Foo
include Kontena::Wait::Helper
def foo
wait_until { ... }
end
end However, there's not really that much benefit to mixing in those methods... what about? Kontena.wait_util { ... } In preference to monkey-patching |
Yes... I need to figure out how that works, the gems probably do need to get published in the end in order to be able to use them in the CLI. However, having the common gems in the same git repo and using the same version numbering would still be an advantage. |
( module Baz
module_function
def foo
puts "bar"
end
def bar
puts "foo"
end
end
Baz.foo
Baz.bar
Class.new { include Baz }.new.foo # private method foo called ) |
Some of the kontena components share code, which is currently copy-pasted between components, with small variations. Introduce a new top-level
common/lib
path in the form of an unpublishedkontena-common
gem, which is loaded directly from the local path. This requires the Docker images to be built in the top-level project context, but brings with it the advantages of a monorepo for tightly integrated code under active development: the ability to both change the common code and all callers in the same PR, and no need for separate versioning/publishing of the common code for every trivial change.Changes
Refactor the agent to use the following
kontena-common
classes, intended to be shared with the server:Kontena::Logging
Kontena::Wait::Helper
TODO
kontena-common
version to use./VERSION
kontena-common
gem from the cli code (not built as a Docker image, but published as a gem)