Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F12423889
registry.rs
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
registry.rs
View Options
use
lazy_static
::
lazy_static
;
use
log
::
error
;
use
regex
::
Regex
;
use
serde_derive
::
{
Deserialize
,
Serialize
};
use
std
::
fs
::
{
DirEntry
,
File
,
read_dir
};
use
std
::
io
::
{
Read
,
Result
as
IOResult
};
use
std
::
path
::
Path
;
/* -------------------------------------------------------------
Registry
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/// Represents a Docker registry
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all =
"camelCase"
)]
pub
struct
Registry
{
#[serde(skip_serializing)]
pub
directory
:
String
,
pub
repositories_count
:
i32
}
impl
Registry
{
const
DEFAULT_LOCATION
:
&
'
static
str
=
"/var/lib/registry"
;
pub
fn
new
(
directory
:
String
)
->
Self
{
let
mut
registry
=
Registry
{
directory
,
repositories_count
:
0
,
};
registry
.
update_stats
();
registry
}
pub
fn
with_default_location
()
->
Self
{
Self
::
new
(
String
::
from
(
Self
::
DEFAULT_LOCATION
))
}
pub
fn
update_stats
(
&
mut
self
)
{
self
.
repositories_count
=
self
.
count_repositories
();
}
pub
fn
count_repositories
(
&
self
)
->
i32
{
let
path_name
=
self
.
get_repositories_path
();
let
path
=
Path
::
new
(
&
path_name
);
if
path
.
exists
()
&&
path
.
is_dir
()
{
match
count_subdirectories
(
path
)
{
Ok
(
n
)
=>
n
as
i32
,
Err
(
e
)
=>
{
error
!
(
target
:
"api"
,
"Can't count registry directories: {}"
,
e
);
0
}
}
}
else
{
error
!
(
target
:
"api"
,
"Registry path doesn't exist or isn't a directory: {}"
,
path_name
);
0
}
}
pub
fn
get_repositories_path
(
&
self
)
->
String
{
format
!
(
"{}/docker/registry/v2/repositories"
,
self
.
directory
)
}
pub
fn
get_repository
(
&
self
,
repository_name
:
&
str
)
->
Option
<
Repository
>
{
if
!
Repository
::
is_valid_name
(
repository_name
)
{
return
None
}
let
path
=
Path
::
new
(
&
self
.
get_repositories_path
()).
join
(
repository_name
);
let
directory
=
match
path
.
as_path
().
to_str
()
{
Some
(
name
)
=>
String
::
from
(
name
),
None
=>
{
return
None
;
}
};
let
mut
repository
=
Repository
{
directory
,
name
:
String
::
from
(
repository_name
),
tags
:
Vec
::
new
(),
};
repository
.
update_tags
();
Some
(
repository
)
}
pub
fn
get_all_repositories
(
&
self
)
->
Vec
<
Repository
>
{
let
path
=
self
.
get_repositories_path
();
let
path
=
Path
::
new
(
&
path
);
get_subdirectories_names
(
path
)
.
iter
()
.
filter_map
(
|
name
|
self
.
get_repository
(
&
name
))
.
collect
()
}
pub
fn
get_repositories_by_layer_hash
(
&
self
,
hash
:
&
str
)
->
Vec
<
Repository
>
{
self
.
get_all_repositories
()
.
into_iter
()
.
filter
(
|
repo
|
repo
.
has_layer
(
hash
))
.
collect
()
}
pub
fn
get_repositories_by_image_hash
(
&
self
,
hash
:
&
str
)
->
Vec
<
Repository
>
{
self
.
get_all_repositories
()
.
into_iter
()
.
filter
(
|
repo
|
repo
.
has_image
(
hash
))
.
collect
()
}
}
/* -------------------------------------------------------------
Repository
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/// Represents a repository from the Docker registry
#[derive(Serialize, Deserialize)]
#[serde(rename_all =
"camelCase"
)]
pub
struct
Repository
{
#[serde(skip_serializing)]
pub
directory
:
String
,
pub
name
:
String
,
pub
tags
:
Vec
<
Tag
>
,
}
impl
Repository
{
pub
fn
exists
(
&
self
)
->
bool
{
let
path
=
Path
::
new
(
&
self
.
directory
);
path
.
exists
()
&&
path
.
is_dir
()
}
pub
fn
is_valid_name
(
name
:
&
str
)
->
bool
{
lazy_static
!
{
static
ref
RE
:
Regex
=
Regex
::
new
(
"^[a-zA-Z0-9_-]+$"
).
unwrap
();
}
RE
.
is_match
(
name
)
&&
name
.
len
()
<=
30
}
pub
fn
is_valid_hash
(
hash
:
&
str
)
->
bool
{
lazy_static
!
{
static
ref
RE
:
Regex
=
Regex
::
new
(
"^[a-f0-9]+$"
).
unwrap
();
}
RE
.
is_match
(
hash
)
&&
hash
.
len
()
==
64
}
pub
fn
update_tags
(
&
mut
self
)
{
let
path
=
Path
::
new
(
&
self
.
directory
).
join
(
"_manifests/tags"
);
let
tag_names
=
get_subdirectories_names
(
&
path
);
self
.
tags
=
tag_names
.
iter
()
.
map
(
|
name
|
Tag
{
name
:
name
.
clone
(),
hash
:
self
.
get_hash_for_tag
(
&
name
).
unwrap_or
(
String
::
new
()),
})
.
collect
();
}
fn
get_hash_for_tag
(
&
self
,
tag_name
:
&
str
)
->
IOResult
<
String
>
{
let
mut
buffer
=
String
::
new
();
let
path
=
Path
::
new
(
&
self
.
directory
)
.
join
(
"_manifests/tags"
)
.
join
(
tag_name
)
.
join
(
"current/link"
);
let
mut
f
=
File
::
open
(
path
)
?
;
f
.
read_to_string
(
&
mut
buffer
)
?
;
buffer
=
Tag
::
clean_tag
(
&
buffer
);
Ok
(
buffer
)
}
pub
fn
has_layer
(
&
self
,
layer_hash_to_seek
:
&
str
)
->
bool
{
let
path
=
Path
::
new
(
&
self
.
directory
).
join
(
"_layers/sha256"
);
get_subdirectories_names
(
&
path
)
.
iter
()
.
any
(
|
hash
|
hash
==
layer_hash_to_seek
)
}
pub
fn
has_image
(
&
self
,
image_hash_to_seek
:
&
str
)
->
bool
{
let
path
=
Path
::
new
(
&
self
.
directory
).
join
(
"_manifests/revisions/sha256"
);
get_subdirectories_names
(
&
path
)
.
iter
()
.
any
(
|
hash
|
hash
==
image_hash_to_seek
)
}
}
/* -------------------------------------------------------------
Tag
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/// Represents a repository tag
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all =
"camelCase"
)]
pub
struct
Tag
{
pub
name
:
String
,
pub
hash
:
String
,
}
impl
Tag
{
pub
fn
clean_tag
(
tag
:
&
str
)
->
String
{
let
fragments
:
Vec
<&
str
>
=
tag
.
split
(
":"
).
collect
();
if
fragments
.
len
()
==
1
{
String
::
from
(
tag
)
}
else
{
String
::
from
(
fragments
[
1
])
}
}
}
/* -------------------------------------------------------------
File system helper functions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
fn
count_subdirectories
(
dir
:
&
Path
)
->
IOResult
<
usize
>
{
let
count
=
read_dir
(
dir
)
?
.
filter
(
|
entry
|
is_entry_sub_directory
(
entry
))
.
count
();
Ok
(
count
)
}
fn
is_entry_sub_directory
(
entry
:
&
IOResult
<
DirEntry
>
)
->
bool
{
match
entry
{
Ok
(
e
)
=>
e
.
path
().
is_dir
(),
Err
(
_
)
=>
false
,
}
}
fn
get_entry_name
(
entry
:
&
IOResult
<
DirEntry
>
)
->
String
{
match
entry
{
Ok
(
e
)
=>
match
e
.
file_name
().
into_string
()
{
Ok
(
name
)
=>
String
::
from
(
name
),
Err
(
_
)
=>
String
::
new
(),
}
Err
(
_
)
=>
String
::
new
(),
}
}
fn
get_subdirectories_names
(
dir
:
&
Path
)
->
Vec
<
String
>
{
match
std
::
fs
::
read_dir
(
dir
)
{
Ok
(
iterator
)
=>
{
iterator
.
filter
(
|
entry
|
is_entry_sub_directory
(
entry
))
.
map
(
|
entry
|
get_entry_name
(
&
entry
))
.
filter
(
|
name
|
name
!=
""
)
.
collect
::
<
Vec
<
_
>>
()
},
Err
(
_
)
=>
{
error
!
(
"Can't get subdirectories of {:?}"
,
dir
);
Vec
::
new
()
}
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Nov 6, 19:20 (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3137560
Default Alt Text
registry.rs (7 KB)
Attached To
Mode
rAPIREG Nasqueron private Docker registry API
Attached
Detach File
Event Timeline
Log In to Comment