Skip to content

Commit

Permalink
feat: remove dependency on OpenPolicyAgent_jll (#17)
Browse files Browse the repository at this point in the history
* feat: remove dependency on OpenPolicyAgent_jll

Removing hard dependency on `OpenPolicyAgent_jll`. Since we allow caller to specify an opa executable, not having a tight dependency will allow calling code to avoid installing the jll at all. So that it will not be affected if the jll is not updated/outdated.

* require opa command to be supplied explicitly

* do not generate CLI code that uses `opa` from path

* remove kwdef constructor for CommandLine

* add convenience constructor for MonitoredOPAServer

* Update src/server/server.jl

Co-authored-by: Morten Piibeleht <[email protected]>

---------

Co-authored-by: Morten Piibeleht <[email protected]>
  • Loading branch information
tanmaykm and mortenpi authored Oct 29, 2024
1 parent e59bc61 commit 792c578
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 33 deletions.
7 changes: 3 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
name = "OpenPolicyAgent"
uuid = "8f257efb-743c-4ebc-8197-d291a1f743b4"
authors = ["JuliaHub Inc.", "Tanmay Mohapatra <[email protected]>"]
version = "0.3.3"
version = "0.4.0"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
OpenAPI = "d5e62ea6-ddf3-4d43-8e4c-ad5e6c8bfd7d"
OpenPolicyAgent_jll = "6ea5c882-2ec3-5826-84d1-aff636352c13"
TimeZones = "f269a46b-ccf7-5d73-abea-4c690281aa53"

[compat]
Dates = "1.6"
OpenAPI = "0.1"
TimeZones = "1"
julia = "1.6"
OpenPolicyAgent_jll = "0.69"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
OpenPolicyAgent_jll = "6ea5c882-2ec3-5826-84d1-aff636352c13"

[targets]
test = ["Test", "JSON", "HTTP"]
test = ["Test", "JSON", "HTTP", "OpenPolicyAgent_jll"]
6 changes: 3 additions & 3 deletions docs/src/commandline.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

The OPA (Open Policy Agent) command-line tool is a versatile utility that empowers users to interact with and manage OPA policies and data. It allows users to perform various tasks, such as evaluating policies, testing Rego expressions, and querying data, all from the command line. This tool is invaluable for policy development, debugging, and troubleshooting, providing an accessible way to work with OPA without the need for complex integration. It's an essential companion for developers and administrators working with OPA, simplifying the process of authoring, testing, and refining policies to ensure robust and consistent policy enforcement across software systems.

The OPA command line is made available in the `OpenPolicyAgent.CLI` module. To use, import the module. E.g.:
The OPA command line is made available in the `OpenPolicyAgent.CLI` module. To use, import the module. It needs the `opa` executable to be made available. The `OpenPolicyAgent_jll` package has the `opa` executable built-in and can be used conveniently. E.g.:

```julia
julia> using OpenPolicyAgent
julia> using OpenPolicyAgent, OpenPolicyAgent_jll

julia> import OpenPolicyAgent: CLI

julia> ctx = CLI.CommandLine();
julia> ctx = CLI.CommandLine(OpenPolicyAgent_jll.opa);

julia> CLI.opa(ctx; help=true);
An open source project to policy-enable your service.
Expand Down
3 changes: 3 additions & 0 deletions docs/src/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ The OPA (Open Policy Agent) server is a critical component of the OPA ecosystem,
The `OpenPolicyAgent.Server` module includes methods to help start the OPA server,
monitor it for failures, and restart when required.

It needs to be supplied with the `opa` executable path. The one bundled with `OpenPolicyAgent_jll` can be used for convenience.

```julia
function start_opa_server(root_path)
opa_server = OpenPolicyAgent.Server.MonitoredOPAServer(
OpenPolicyAgent.CLI.CommandLine(OpenPolicyAgent_jll.opa),
joinpath(root_path, "config.yaml"),
stdout = joinpath(root_path, "server.stdout"),
stderr = joinpath(root_path, "server.stderr"),
Expand Down
4 changes: 1 addition & 3 deletions specs/cli/gencli.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ const SPEC = joinpath(sdir, "opa.json")
const CLIMODULE = joinpath(sdir, "..", "..", "src", "cli", "cli.jl")

const custom_include = """
using OpenPolicyAgent_jll
\"\"\"
CommandLine execution context.
Expand All @@ -15,7 +13,7 @@ CommandLine execution context.
`pipelineopts`: keyword arguments that should be used to further customize the `pipeline` creation
\"\"\"
Base.@kwdef struct CommandLine
exec::Base.Function = OpenPolicyAgent_jll.opa
exec::Base.Function = ()->``
cmdopts::OptsType = OptsType()
pipelineopts::OptsType = OptsType()
runopts::OptsType = OptsType()
Expand Down
25 changes: 15 additions & 10 deletions src/cli/cli.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,25 @@ module CLI

const OptsType = Base.Dict{Base.Symbol,Base.Any}

using OpenPolicyAgent_jll

"""
CommandLine execution context.
`exec`: a no argument function that provides the base command to execute in a julia `do` block.
`cmdopts`: keyword arguments that should be used to further customize the `Cmd` creation
`pipelineopts`: keyword arguments that should be used to further customize the `pipeline` creation
CommandLine(exec; cmdopts, pipelineopts, runopts)
- `exec`: a no argument function that provides the base command to execute in a julia `do` block.
- `cmdopts`: keyword arguments that should be used to further customize the `Cmd` creation
- `pipelineopts`: keyword arguments that should be used to further customize the `pipeline` creation
- `runopts`: additional options to be passed to the `Base.run` method
"""
Base.@kwdef struct CommandLine
exec::Base.Function = OpenPolicyAgent_jll.opa
cmdopts::OptsType = OptsType()
pipelineopts::OptsType = OptsType()
runopts::OptsType = OptsType()
struct CommandLine
exec::Base.Function
cmdopts::OptsType
pipelineopts::OptsType
runopts::OptsType

function CommandLine(exec::Base.Function; cmdopts::OptsType = OptsType(), pipelineopts::OptsType = OptsType(), runopts::OptsType = OptsType())
return new(exec, cmdopts, pipelineopts, runopts)
end
end

""" opa
Expand Down
15 changes: 9 additions & 6 deletions src/server/server.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import Base: Process
const DEFAULT_PORT = 8181

"""
MonitoredOPAServer(configfile::String;
MonitoredOPAServer(
cmdline::CommandLine,
configfile::String;
host::String = "localhost",
port::Int = DEFAULT_PORT,
stdout = nothing,
Expand All @@ -17,6 +19,7 @@ const DEFAULT_PORT = 8181
A server that is monitored and restarted if it dies.
Arguments:
- `cmdline`: The `CLI.CommandLine` instance that wraps an opa executable.
- `configfile`: The path to the OPA configuration file.
Keyword arguments:
Expand All @@ -37,16 +40,14 @@ struct MonitoredOPAServer
stopped::Ref{Bool}
lck::ReentrantLock

function MonitoredOPAServer(configfile::String;
function MonitoredOPAServer(
cmdline::CommandLine,
configfile::String;
host::String = "localhost",
port::Int = DEFAULT_PORT,
stdout = nothing,
stderr = nothing,
cmdline = nothing,
)
if isnothing(cmdline)
cmdline = CommandLine()
end
cmdline.runopts[:wait] = false

return new(configfile,
Expand All @@ -61,6 +62,8 @@ struct MonitoredOPAServer
end
end

MonitoredOPAServer(exec::Function, configfile::String; kwargs...) = MonitoredOPAServer(CommandLine(exec), configfile; kwargs...)

function start_opa_server!(server::MonitoredOPAServer)
ctx = server.cmdline
if !isnothing(server.stdout)
Expand Down
9 changes: 5 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using OpenPolicyAgent
using OpenPolicyAgent_jll
using OpenAPI
using JSON
using HTTP
Expand All @@ -17,8 +18,8 @@ import .OPASQL: translate
function test_version_help()
iob_stdout = IOBuffer()
iob_stderr = IOBuffer()
pipelineopts = Dict(:stdout => iob_stdout, :stderr => iob_stderr)
cmd = OpenPolicyAgent.CLI.CommandLine(; pipelineopts=pipelineopts)
pipelineopts = CLI.OptsType(:stdout => iob_stdout, :stderr => iob_stderr)
cmd = OpenPolicyAgent.CLI.CommandLine(OpenPolicyAgent_jll.opa; pipelineopts=pipelineopts)
CLI.version(cmd)
if Sys.iswindows()
sleep(10) # Windows is slow to flush the buffers
Expand All @@ -28,8 +29,8 @@ function test_version_help()

iob_stdout = IOBuffer()
iob_stderr = IOBuffer()
pipelineopts = Dict(:stdout => iob_stdout, :stderr => iob_stderr)
cmd = OpenPolicyAgent.CLI.CommandLine(; pipelineopts=pipelineopts)
pipelineopts = CLI.OptsType(:stdout => iob_stdout, :stderr => iob_stderr)
cmd = OpenPolicyAgent.CLI.CommandLine(OpenPolicyAgent_jll.opa; pipelineopts=pipelineopts)
CLI.help(cmd)
if Sys.iswindows()
sleep(10) # Windows is slow to flush the buffers
Expand Down
7 changes: 4 additions & 3 deletions test/test_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
function prepare_bundle(bundle_location::String)
signed_bundle_file = joinpath(bundle_location, "data.tar.gz")
run(`rm -f $signed_bundle_file`)
CLI.build(OpenPolicyAgent.CLI.CommandLine(; cmdopts=Dict(:dir => data_bundle_root)),
CLI.build(CLI.CommandLine(OpenPolicyAgent_jll.opa; cmdopts=CLI.OptsType(:dir => data_bundle_root)),
".";
output=signed_bundle_file,
bundle_args...
)

signed_bundle_file = joinpath(bundle_location, "policies.tar.gz")
run(`rm -f $signed_bundle_file`)
CLI.build(OpenPolicyAgent.CLI.CommandLine(; cmdopts=Dict(:dir => policies_bundle_root)),
CLI.build(CLI.CommandLine(OpenPolicyAgent_jll.opa; cmdopts=CLI.OptsType(:dir => policies_bundle_root)),
".";
output=signed_bundle_file,
bundle_args...
Expand Down Expand Up @@ -45,13 +45,14 @@ end
function start_opa_server(root_path; change_dir::Bool=true)
if change_dir
opa_server = OpenPolicyAgent.Server.MonitoredOPAServer(
CLI.CommandLine(OpenPolicyAgent_jll.opa; cmdopts=CLI.OptsType(:dir => root_path)),
joinpath(root_path, "config.yaml");
stdout = joinpath(root_path, "server.stdout"),
stderr = joinpath(root_path, "server.stderr"),
cmdline = OpenPolicyAgent.CLI.CommandLine(; cmdopts=Dict(:dir => root_path)),
)
else
opa_server = OpenPolicyAgent.Server.MonitoredOPAServer(
OpenPolicyAgent_jll.opa,
joinpath(root_path, "config.yaml");
stdout = joinpath(root_path, "server.stdout"),
stderr = joinpath(root_path, "server.stderr"),
Expand Down

2 comments on commit 792c578

@tanmaykm
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/118279

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.4.0 -m "<description of version>" 792c5783371e1ae17c24255cd068f6025ec839fc
git push origin v0.4.0

Please sign in to comment.