►
From YouTube: Building re-usable operators with controller-idioms
Description
No description was provided for this meeting.
If this is YOUR meeting, an easy way to fix this is to add a description to your video, wherever mtngs.io found it (probably YouTube).
A
A
My
name
is
Evan
Cordell
I'm,
a
software
engineer
at
offset
where
we're
building
a
distributed
permissions
database
called
spice
DB,
similar
to
Google
Zanzibar
system.
If
you're
familiar
I
did
want
to
mention
before
I
get
too
far
into
it,
that
I'm
going
to
assume
some
prior
knowledge
of
kubernetes
and
controllers
and
operators
and
golang.
A
They
might
ensure
that
some
resource
exists
in
a
cluster
with
a
particular
configuration,
maybe
creating
a
deployment
in
response
to
some
API
call,
making
a
job
making
a
service
deleting
duplicates
that
it
doesn't
think
need
to
exist,
or
they
might
do
something
like
wait
for
some
condition
to
be
present
waiting
for
a
job
to
finish
a
deployment
to
be
fully
available
service
to
have
endpoints
things
like
that,
or
they
might
need
to
start
watching
a
new
resource
because
it's
been
referenced
by
another
object
that
it
watches
and
it
needs
to
start
watching
the
new
things.
A
So
there's
these
really
common
building
blocks
that
we
use
to
build
operators.
Those
are
just
some
examples,
but
we
end
up
writing
them
from
scratch.
Almost
every
time,
there's
a
lot
of
great
libraries
out
there
that
help
with
some
of
the
low
level
complexity
of
talking
to
kubernetes
and
building
a
controller
things
like
controller
runtime
operator,
SDK,
Cube
Builder,
but
we
still
end
up
rewriting
these
same
basic
workflows
over
and
over
again,
you
know
create
the
service.
You
know
we
use
a
client
to
do
that.
Things
like
that
and
operators
are
essentially
State
machines.
A
They
read
the
kubernetes
state
from
the
API.
They
make
some
decisions
based
on
that
state
and
then
they
do
stuff
based
on
it.
What's
kind
of
interesting
about
operators.
Is
that
they're
really
really
big
state
machines
and
I
kind
of
think
that
this
is
what
drives
our
lack
of
reuse,
because
when
you
have
big
state
machines
like
this
you're,
often
using
the
previous
States,
the
previous
context,
to
make
decisions
about
what
to
do
so,
you
might
decide
whether
or
not
to
create
an
object
in
the
Kube
API,
based
on
other
actions.
A
So
that's
kind
of
where
controller
idioms
comes
in.
That's
what
we're
trying
to
solve.
How
do
we
make
the
steps
in
a
state
machine
reusable
for
a
controller,
but
you
might
be
asking
why
I'm
talking
about
this?
Why
we're
talking
about
it
now?
What's
going
on
so
I
mentioned
this
at
the
top,
but
we're
building
an
open
source
implementation
of
Zanzibar
called
spice
DB.
A
If
you
want
to
check
that
out
to
run
that,
we
also
wrote
the
space
DB
operator
to
run
it
on
kubernetes,
which
is
open
source,
you
can
look
through
it
and
then
our
hosted
Services
we
call
off
the
dedicated
is
built
on
top
of
a
set
of
additional
operators
that
are
currently
not
open
source.
A
lot
of
us
are
former
kuros
red
hat
and
operator
framework
Alum,
so
we're
familiar
with
operators.
A
We
really
believe
in
their
value
and
they
let
us
deliver
software
to
our
own
users
quickly
and
safely,
but
because
we're
writing
all
these
operators.
We
kept
seeing
these
same
patterns
across
all
of
them
and
trying
to
come
up
with
a
way
to
share
them
between
all
of
our
implementations.
So
that's
kind
of
why
we're
doing
this
right
now
we're
building
lots
of
operators.
We
have
experience
building
operators
and
we
want
to
make
it
simpler
for
ourselves
and
share
that
with
others.
A
A
It's
also
really
helpful
for
things
like
testing
and
composition
and
that
kind
of
thing,
but
I'm
just
going
to
start
with
this
basic
interface
handle
which
probably
looks
pretty
familiar
if
you're
familiar
with
golang,
because
this
is
essentially
the
same
as
the
HTTP
server
interface,
and
this
is
going
to
be
our
building
block
for
making
large
controllers
I
did
want
to
mention
that
this
really
isn't
any
particular
framework
specific.
You
could
do
this
with
controller
runtime.
A
A
So
if
all
of
our
little
bits
of
a
big
controller
are
broken
down
into
these
small
handle
functions,
these
handlers,
we
still
need
a
way
to
pass
context
between
them,
because
we
don't
want
to
always
recompute
all
the
data
that
we
need.
We
can
and
controllers
often
have
access
to
huge
swaths
of
cache
data
to
recompute
state,
but
it's
not
ideal.
A
Ideally
we're
not
recomputing
things
all
the
time
in
every
Handler,
just
to
keep
them
decoupled
for
testing,
and
so
obviously,
golang
has
this
great
context
package
that's
used
everywhere,
but
now
with
golang
118,
we
can
build
some
nicer
abstractions
around
those
using
typed
accessors.
So
one
of
the
things
that
controller
idioms
includes
is
this
typed
accessory,
Library
typed
context
that
lets
you
create
keys
that
index
into
a
context
and
let
you
pop
out
values
of
a
particular
kind.
A
This
is
not
really
operator
specific
at
all,
but
it
ends
up
being
really
useful
when
you're
writing
handlers
and
you
want
to
transmit
values
between
them.
So
in
this
case,
I
have
two
handlers.
One
of
them
does
some
expensive
computation
stashes
that
into
a
context
and
then
in
a
later
Handler.
We
extract
the
value
back
out,
so
it's
probably
not
super
obvious
that
these
compose
well
and
I
would
say
right
now.
They
don't
I,
haven't
gotten
to
that
yet,
but
you
can
imagine
some
sort
of
synchronization
function.
That's
calling
these
handlers!
A
So
what
we
could
do
is
we
could
do
something
like
this.
We
could
just
say:
okay,
we'll
sync
calls
Handler
one
and
then
Handler
one
calls
Handler
two
which
does
work
because
now
Handler
2
has
all
the
context
that
handler1
had
and
can
grab
values
back
out
of
it.
If
you
imagine
the
earlier
example
with
some
expensive
computation
done
in
Handler
one
now,
Handler
2
can
pull
that
back
out
without
recomputing
it,
but
this
does
make
it
a
little
harder
to
rearrange
and
it's
not.
A
A
So
this
is
where
the
Builder
type
comes
in,
which
is
a
function
that
takes
in
a
set
of
handlers
and
returns,
a
new
Handler,
which
is
maybe
not
too
exciting.
But
what
this
lets
us
do
is
think
about
injecting
the
next
Handler
that
a
Handler
calls
dynamically
in
a
way
that
we
can
rearrange
later.
A
So
here's
an
example
using
a
function
chain
which
is
part
of
controller
idioms,
which
will
first
run
the
first
Builder
to
create
a
Handler
then
run
the
second
Builder
to
create
a
Handler
and
it'll
run
the
two
handlers
in
order
passing
the
context
in
between
them,
so
that
they
do
have
the
the
values
shared,
and
you
can
imagine
rearranging
these
two.
You
could
flip
them
back
around
and
do
second
Builders
and
in
first
Builders,
so
the
second
one
is
called
first
and
I
can
rearrange
this
without
rewriting
either
of
them.
A
Now
the
only
caveat
there
is
that
they
may
have
different
expectations
around
what
values
exist
in
the
context,
depending
on
where
they
are
in
the
chain,
and
so
that
is
why
there's
lots
of
helpers
around
ensuring
that
the
context
has
what
you
expect
it
to
do,
and
in
a
bigger
controller,
it's
not.
Every
step
in
a
chain
will
depend
on
every
other
step
of
the
chain,
so
it
makes
it
a
little
easier
to
do
things
like
rearranging
when
when
needs
change.
A
So
another
example
is
the
parallel
helper,
which
does
essentially
the
same
thing
as
the
chain
function.
But
in
this
case,
both
run
in
parallel
with
the
same
input
context.
So
in
this
case
they
don't
actually
aren't.
They
aren't
able
to
affect
each
other's
context
at
all
so
kind
of
we
fix
the
problem
with
chain
and
now
we've
broken
it
again
with
parallel.
We
don't
get
the
values
back
out
of
context,
so
I'm
going
to
come
back
to
how
this
is
solved,
but
another
way
that
you
can
compose
handlers
is
via
wrapping.
A
If
I
have
some
existing
Handler
I
can
stick
it
inside
of
another
Handler
and
call
it
and
then
I
can
check
and
see
if
there's
been
any
errors
there
now.
The
thing
here
is
that
the
context
that
is
modified
by
the
wrapped,
Handler
isn't
accessible
from
the
wrapper
and
so
there's
some
helpers
in
the
same
typed
context
package
that
helps
deal
with
this
problem.
Instead
of
of
just
putting
a
value
in
the
context.
A
A
And
then
one
other
way
that
we
can
compose
handlers
is
via
branching.
In
this
case,
we
have
these
Handler
keys
that
identify
a
specific
Handler
out
of
a
big
set,
so
you
could
do
something
like
in
this
example,
I
have
a
sync
function.
That
first
looks
at
the
object
to
decide
if
it's
been
deleted
or
not
and
then
branches
into
two
different
Handler
chains
based
on
that
decision.
So
this
would,
let
me
have
defined
elsewhere,
like
a
full
chain
of,
if
it's
deleted
hand,
layers
versus
a
full
chain
of
if
it's
not
deleted
handlers.
A
So
there
are
these
helpers
for
dealing
with
sets
of
other
handlers
and
picking
out
the
right
one
and
giving
them
identifiers,
and
things
like
that.
So
now
that
we
have
a
way
to
compose
controllers
and
build
them
up
out
of
smaller
pieces,
we
can
also
more
easily
talk
about.
You
know:
Common
patterns
and
encoding.
Those
with
these
libraries
and
that's
kind
of
what
the
rest
of
controller
idioms
is.
The
first
bit
is
the
basic
building
blocks
to
make
things
reusable.
A
So
the
first
idiom
is
adoption.
This
comes
up
a
lot
when
controllers
are
trying
to
be
efficient
with
the
resources
they
watch.
So,
for
example,
you
could
write
a
controller
that
watches
every
config
map
in
a
cluster
and
then,
when
someone
references
a
config
map
in
an
object,
you
will
have
that
config
map
in
your
cache
already,
because
you're
watching
all
config
Maps
most
people
don't
want
to
watch
all
config
Maps
both
for
like
security
reasons
and
then
also
just
for
space
reasons.
A
But
then,
of
course,
you
have
a
problem
where,
if
the
operator
is
not
the
one
creating
the
config
map,
it
can't
put
that
label
on
it,
so
it
won't
be
in
its
cache.
So
this
is
an
issue
for
any
resource
that
is
used
as
input
to
a
controller
rather
than
as
output,
and
this
is
what
we
call
the
adoption
workflow
when
some
custom
resources
created
that
references.
Another
object,
that's
already
existing
in
the
cluster.
A
We
first
check
and
see
if
it
exists
and
then,
if
it
does,
we
add
whatever
the
special
operator
label
is
the
operator
is
watching,
and
that
brings
the
object
into
the
operator's
watch
stream
and
cache.
And
now
the
operator
can
know
that
it's
there
and
continue
working
with
that
object,
going
forward.
A
Another
one
that
we
use
a
lot,
we
call
the
component
idiom,
and
this
really
is
just
when
the
operator
is
in
full
control
over
some
external
resource
that
it
creates
in
response
to
user
input.
So
a
user
creates
a
custom
object
and
then
we
need
to
create
a
deployment
based
on
that
object
or
a
service
whatever.
A
In
that
case
the
operator
is
creating
it
and
it's
you
know,
has
some
uniqueness
property,
it's
one
to
one
or
many
to
one
with
the
object.
The
user
created
generally
life
cycled
with
it,
so
it
might
have
owner
references.
It's
really
not
supposed
to
be
shared
with
other
controllers.
This
is
a
relatively
common
pattern
that
some
operators
use,
and
so
we've
encoded
this
in
controller
idioms
as
well,
so
that
it
will
handle
the
kind
of
the
Dirty
Work
of
creating
the
object.
A
A
Another
idiom
we're
calling
static
resources,
which
is
when
a
controller
is
given
some
definition
of
an
object,
and
it
just
makes
sure
that
object
exists
and
matches
exactly.
This
can
be
really
useful
for
bootstrapping.
If
you
have
a
controller
that
you
know
needs
to
create
some
default
resources
when
it
starts
up.
This
can
be
really
a
useful
way
to
do
that.
It
could
also
be
some
sort
of
operator
Global
config.
A
If
you
have
something
along
those
lines
that
needs
to
just
always
exist
when
the
operator
is
running
another
one
is
the
positium
where
it
can
often
be
useful
to
tell
a
controller
not
to
stop
entirely
but
to
stop
processing
a
specific
object.
It's
going
to
be
especially
useful.
If
you
need
to
go
in
and
do
some
debugging
deal
with
you
know,
human
operator
needs
stop
it
from
doing
something
crazy.
That
kind
of
thing.
A
A
I
was
going
to
briefly
go
over
these
I
think
they're
they're,
really
in
support
of
everything
else,
but
we
have
some
basic
caching
libraries
that
wrap
hashing
and
validating
hashes.
There's
some
utilities
for
work,
Key
Management,
if
you're,
if
you're
using
client,
go
probably
not
something
you'd
want
to
use
if
you're
using
controller
runtime.
It
has
some
common
metrics
to
emit
if
you're
using
standard
conditions,
for
example,
this
will
emit
metrics
based
on
the
conditions.
A
It
does
come
with
a
basic
controller
and
controller
manager.
Implementation,
if
you
don't
want
to
use
one
of
the
other
libraries
like
clango
or
or
controller
runtime,
for
that
it
does
have
a
file
Informer,
which
essentially
works
the
same
as
other
communities,
API
informers,
but
it
reads
from
a
local
file.
A
So
that's
that's
kind
of
it.
That's
the
the
overall,
that's
the!
What
the
problem
is.
That's
how
we
think
about
breaking
down
the
problem
and
how
we've
built
some
abstractions
to
help
with
this
at
auth
said.
If
you
want
to
know
more,
you
can
definitely
check
out
the
controller
idioms,
repo
repo
and
now,
if
you
have
questions
or
ideas,
or
you
know
with
still
early
days,
if
it's
a
lot
of
stuff
we
haven't
identified,
that
would
be
a
great
addition
to
the
library.
A
So
if
you
want
to
add
something,
there
it'd
be
a
great
opportunity.
A
If
you
want
to
see
how
controller
idioms
are
used
in
practice,
I
have
a
link
to
the
spicyb
operator
here,
which
is
open
source.
You
can
look
through
how
we
use
controller
idioms
all
over
that
and
then,
if
you
just
want
to
chat
or
just
get
in
touch,
we
have
a
Discord
that
you
can
come
talk
about
it
or
you
can
get
in
touch
on
Twitter.
A
So
thanks
for
listening
and
have
a
nice
day.