Skip to content
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

RFC: generalize resource interface #24

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6fd41f9
initial generalized resources proposal
vito Apr 3, 2019
2850500
i guessed the number wrong :(
vito Apr 3, 2019
50a272a
start defining important terms, tweak wording
vito Apr 3, 2019
9554b97
glossary updates, add icon support as motivation
vito Apr 4, 2019
7e78e1e
start interface outline, artifacts interpretation
vito Apr 4, 2019
ed3b28a
fix bare links, + other minor cleanups
vito Apr 4, 2019
3ca8f96
clarify reasoning for ./info being relative
vito Apr 4, 2019
b5e332e
change formatting of 'versioned artifact' section
vito Apr 4, 2019
0edb683
flesh out 'check' interface
vito Apr 4, 2019
f8e7164
give 'check' events an event type
vito Apr 4, 2019
e90ed7f
make linter happy
vito Apr 7, 2019
836eb67
add 'delete' action, unify action interface
vito Apr 7, 2019
999a803
execute default command for image, not ./info
vito Apr 8, 2019
1e611ee
fix a couple of link titles
vito Apr 8, 2019
aec9032
update artifact check semantics, add git example
vito Apr 8, 2019
0b42c11
bring artifact resources description up to date
vito Apr 8, 2019
80f3ce1
add proposals for notifications/spaces/triggers
vito Apr 8, 2019
1303510
give overview of other workflows and link to them
vito Apr 8, 2019
4b3c95d
bring TLS configuration into the interface
vito Apr 8, 2019
d6eb993
leave rich metadata out-of-scope
vito Apr 8, 2019
0a805ec
add 'previous discussions' section
vito May 13, 2019
2cd1d64
namespace icons
vito May 14, 2019
b2b5b1c
clearer wording
vito May 15, 2019
e63bd67
flesh out artifact resources proposal
vito May 21, 2019
5ae7100
remove proposals for resource interpretations
vito May 21, 2019
fb62380
don't list trigger/spatial/notification resources
vito May 21, 2019
b974dc2
insecure_skip_verify -> skip_verification
vito May 22, 2019
504a13a
flesh out summary and interpretation sections
vito May 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions 024-artifact-resources/examples/git-v2/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM alpine

RUN apk add git ruby ruby-json ruby-bundler build-base ruby-dev cmake openssl-dev

ENV GEM_HOME="/usr/local/bundle"
ENV PATH $GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH
ADD Gemfile .
RUN bundle install

ADD git-resource.rb /usr/bin/git-resource
RUN chmod +x /usr/bin/git-resource

WORKDIR /tmp/request

CMD ["git-resource", "info"]
4 changes: 4 additions & 0 deletions 024-artifact-resources/examples/git-v2/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source :rubygems

gem 'rugged'
gem 'pry'
19 changes: 19 additions & 0 deletions 024-artifact-resources/examples/git-v2/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
GEM
remote: http://rubygems.org/
specs:
coderay (1.1.2)
method_source (0.9.2)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rugged (0.28.1)

PLATFORMS
ruby

DEPENDENCIES
pry
rugged

BUNDLED WITH
1.16.2
115 changes: 115 additions & 0 deletions 024-artifact-resources/examples/git-v2/git-resource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env ruby

require "json"
require "rugged"
require "pry"
require "benchmark"

$request = JSON.parse(STDIN.read, symbolize_names: true)

def commit_fragment(commit)
JSON.dump({
config: {ref: commit.oid},
metadata: [
{name: "author", value: enc(commit, commit.author[:name])},
{name: "committer", value: enc(commit, commit.committer[:name])},
{name: "message", value: enc(commit, commit.message)}
]
})
end

def icon(uri)
case uri
when /github/
"github-circle"
when /gitlab/
"gitlab"
when /bitbucket/
"bitbucket"
else
"git"
end
end

def bench(label, &blk)
time = Benchmark.realtime(&blk)
$stderr.puts "#{label}: #{time}s"
end

def enc(commit, str)
str = str.force_encoding("ISO-8859-1") unless commit.header_field("Encoding")
str.encode("UTF-8")
end

case ARGV[0]
when "info"
puts JSON.dump({
"interface_version": "2.0",
"icon": icon($request[:config][:uri]),
"actions": {
"check": "git-resource check",
"get": "git-resource get",
"put": "git-resource put"
# delete is unsupported
}
})

when "check"
repo =
if File.exists?("HEAD")
Rugged::Repository.new(".").tap do |r|
r.fetch("origin")
end
else
Rugged::Repository.clone_at(
$request[:config][:uri],
".",
checkout_branch: $request[:config][:branch],
bare: true,
progress: lambda { |t| $stderr.print t })
end

walker = Rugged::Walker.new(repo)
walker.sorting(Rugged::SORT_TOPO|Rugged::SORT_REVERSE)
walker.simplify_first_parent
walker.push(repo.head.target)

response = File.new $request[:response_path], 'w'
total_commits = 0

from = $request[:config][:ref]
if from && repo.include?(from)
commit = repo.lookup(from)
walker.hide(commit)

response.puts commit_fragment(commit)
total_commits += 1
end

bench("walk") do
walker.walk do |c|
response.puts commit_fragment(c)
total_commits += 1
end
end

$stderr.puts "commits: #{total_commits}"

response.close

when "get"
repo =
Rugged::Repository.clone_at(
$request[:config][:uri],
".",
checkout_branch: $request[:config][:branch])

repo.checkout($request[:config][:ref])

response = File.new $request[:response_path], 'w'
response.puts commit_fragment(repo.head.target)
response.close

when "put"
puts "putting"
end
57 changes: 57 additions & 0 deletions 024-artifact-resources/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Artifact Resources

This proposal uses the [generalized resource interface](../024-generalized-resources/proposal.md) to show how the interface would be implemented and interpreted by Concourse to support "artifact resources", today's primary use case for v1 resources.

## Motivation

* Support for creating multiple versions from `put`: [concourse/concourse#2660](https://github.com/concourse/concourse/issues/2660)

* Support for deleting versions: [concourse/concourse#362](https://github.com/concourse/concourse/issues/362), [concourse/concourse#524](https://github.com/concourse/concourse/issues/524)

* Make the `get` after `put` opt-in: [concourse/concourse#3299](https://github.com/concourse/concourse/issues/3299), [concourse/registry-image-resource#16](https://github.com/concourse/registry-image-resource/issues/16)

## Examples

* A basic implementation of the `git` resource can be found in [`git-v2`](examples/git-v2).

## Proposal

A v2 resource type can be used as a versioned artifact resource by treating the **config fragments** as **versions** and emitting them in chronological order from `check`. This way the resource type is used to model change in an external resource over time.

### `check`: discover versions in order

The `check` action will first be run with a "naked" config, containing only what the user specified. In this situation `check` must emit an `ActionResponse` for all versions discovered in the config, in chronological order.

Subsequent calls to `check` will be given a config that has been spliced with the last emitted version config fragment. The `check` script must an `ActionResponse` for the given version if it still exists, followed by a response for any versions that came after it.

If the specified version is no longer present, the `check` action must go back to returning all versions, as if the version was not specified in the first place. Concourse will detect this scenario by noticing that the first `ActionResponse` emitted does not match the requested version. All versions that existed before that were emitted will be automatically marked "deleted".

The `check` action can use the **bits** directory to cache state between runs of the `check` on that worker. On the first run, the directory will be empty.

### `get`: fetch a version of an artifact

The `get` action will always be invoked with a spliced config specifying which version to fetch. It is given an empty **bits** directory in which to fetch the data.

An `ActionResponse` must be emitted for all versions that have been fetched into the bits directory. Each version will be recorded as an input to the build.

### `put`: idempotently create artifact versions

The `put` action will be invoked with user-provided configuration and arbitrary bits.

An `ActionResponse` must be emitted for all versions that have been created/updated. Each version will be recorded as an output of the build.

### `delete`: idempotently destroy artifact versions

The `delete` action will be invoked with user-provided configuration and arbitrary bits.

An `ActionResponse` must be emitted for all versions that have been destroyed. These versions will be marked "deleted" and no longer be available for use in other builds.

## Open Questions

* [resource-determined triggerability of versions?](https://github.com/concourse/rfcs/issues/11)
* webhooks?
* should these instead be something supported by *Concourse*?

## Answered Questions

* Version filtering is probably best left to `config`.
Loading