Skip to content

Commit 3a6e5cb

Browse files
feat: add download info to charm
Adding download info to charm allows us to ensure that we correctly store the charm information once and only once.
1 parent 9bfa736 commit 3a6e5cb

File tree

28 files changed

+1010
-284
lines changed

28 files changed

+1010
-284
lines changed

apiserver/facades/client/application/deploy.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
coremodel "github.com/juju/juju/core/model"
2222
"github.com/juju/juju/core/objectstore"
2323
coreunit "github.com/juju/juju/core/unit"
24+
applicationcharm "github.com/juju/juju/domain/application/charm"
2425
applicationservice "github.com/juju/juju/domain/application/service"
2526
machineerrors "github.com/juju/juju/domain/machine/errors"
2627
"github.com/juju/juju/environs/bootstrap"
@@ -169,6 +170,9 @@ func DeployApplication(
169170
_, err = applicationService.CreateApplication(ctx, args.ApplicationName, args.Charm, args.CharmOrigin, applicationservice.AddApplicationArgs{
170171
ReferenceName: chURL.Name,
171172
Storage: args.Storage,
173+
// TODO (stickupkid): Fill this in correctly when we have the
174+
// charmhub information.
175+
DownloadInfo: &applicationcharm.DownloadInfo{},
172176
}, unitArgs...)
173177
if err != nil {
174178
return nil, errors.Trace(err)

apiserver/facades/client/application/deployrepository.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ func (api *DeployFromRepositoryAPI) DeployFromRepository(ctx context.Context, ar
171171
_, addApplicationErr = api.applicationService.CreateApplication(ctx, dt.applicationName, ch, dt.origin, applicationservice.AddApplicationArgs{
172172
ReferenceName: dt.charmURL.Name,
173173
Storage: dt.storage,
174+
// TODO (stickupkid): Fill this in correctly when we have the
175+
// charmhub information.
176+
DownloadInfo: &applicationcharm.DownloadInfo{},
174177
}, unitArgs...)
175178
}
176179

apiserver/facades/client/charms/client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ func (a *API) queueAsyncCharmDownload(ctx context.Context, args params.AddCharmW
311311
ReferenceName: charmURL.Name,
312312
Revision: revision,
313313
Hash: metaRes.ResolvedOrigin.Hash,
314+
// TODO (stickupkid): Fill this information in from the essential
315+
// metadata.
316+
DownloadInfo: &applicationcharm.DownloadInfo{},
314317
}); err != nil && !errors.Is(err, applicationerrors.CharmAlreadyExists) {
315318
return corecharm.Origin{}, errors.Annotatef(err, "setting charm %q", args.URL)
316319
}

apiserver/objects.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ func (h *objectsCharmHTTPHandler) processPut(r *http.Request, st *state.State, c
245245
ArchivePath: storagePath,
246246
Version: version,
247247
Architecture: curl.Architecture,
248+
// If this is a charmhub charm, this will be coming from a migration.
249+
// We can not re-download this charm from the charm store again, without
250+
// another call directly to the charm store.
251+
DownloadInfo: &applicationcharm.DownloadInfo{},
248252
}); err != nil {
249253
return nil, errors.Trace(err)
250254
}

domain/application/charm/types.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ type SetCharmArgs struct {
8282
Version string
8383
// Architecture is the architecture of the charm.
8484
Architecture arch.Arch
85+
// DownloadInfo holds the information needed to download a charmhub charm.
86+
DownloadInfo *DownloadInfo
8587
}
8688

8789
// Revision is the charm revision.
@@ -151,6 +153,20 @@ type CharmLocator struct {
151153
Architecture architecture.Architecture
152154
}
153155

156+
// DownloadInfo holds the information needed to download a charmhub charm.
157+
type DownloadInfo struct {
158+
// CharmhubIdentifier is the instance ID of the charm in relation to
159+
// charmhub.
160+
CharmhubIdentifier string
161+
162+
// DownloadURL is the URL to download the charm from.
163+
DownloadURL string
164+
165+
// DownloadSize is the size of the charm in bytes that the download URL
166+
// points to.
167+
DownloadSize int64
168+
}
169+
154170
// Metadata represents the metadata of a charm from the perspective of the
155171
// service. This is the golden source of charm metadata. If the charm changes
156172
// at the wire format level, we should be able to map it to this struct.

domain/application/errors/errors.go

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,20 @@ const (
1616
// application being created already exists.
1717
ApplicationAlreadyExists = errors.ConstError("application already exists")
1818

19-
// ApplicationNotAlive describes an error that occurs when trying to update an application that is not alive.
19+
// ApplicationNotAlive describes an error that occurs when trying to update
20+
// an application that is not alive.
2021
ApplicationNotAlive = errors.ConstError("application is not alive")
2122

2223
// ApplicationHasUnits describes an error that occurs when the application
2324
// being deleted still has associated units.
2425
ApplicationHasUnits = errors.ConstError("application has units")
2526

26-
// ScalingStateInconsistent is returned by SetScalingState when the scaling state
27-
// is inconsistent with the application scale.
27+
// ScalingStateInconsistent is returned by SetScalingState when the scaling
28+
// state is inconsistent with the application scale.
2829
ScalingStateInconsistent = errors.ConstError("scaling state is inconsistent")
2930

30-
// ScaleChangeInvalid is returned when an attempt is made to set an invalid application scale value.
31+
// ScaleChangeInvalid is returned when an attempt is made to set an invalid
32+
// application scale value.
3133
ScaleChangeInvalid = errors.ConstError("scale change invalid")
3234

3335
// MissingStorageDirective describes an error that occurs when expected
@@ -42,37 +44,39 @@ const (
4244
// not valid.
4345
ApplicationIDNotValid = errors.ConstError("application ID not valid")
4446

45-
// UnitNotFound describes an error that occurs when the unit being operated on
46-
// does not exist.
47+
// UnitNotFound describes an error that occurs when the unit being operated
48+
// on does not exist.
4749
UnitNotFound = errors.ConstError("unit not found")
4850

4951
// UnitAlreadyExists describes an error that occurs when the
5052
// unit being created already exists.
5153
UnitAlreadyExists = errors.ConstError("unit already exists")
5254

53-
// UnitNotAssigned describes an error that occurs when the unit being operated on
54-
// is not assigned.
55+
// UnitNotAssigned describes an error that occurs when the unit being
56+
// operated on is not assigned.
5557
UnitNotAssigned = errors.ConstError("unit not assigned")
5658

57-
// UnitHasSubordinates describes an error that occurs when trying to set a unit's life
58-
// to Dead but it still has subordinates.
59+
// UnitHasSubordinates describes an error that occurs when trying to set a
60+
// unit's life to Dead but it still has subordinates.
5961
UnitHasSubordinates = errors.ConstError("unit has subordinates")
6062

61-
// UnitHasStorageAttachments describes an error that occurs when trying to set a unit's life
62-
// to Dead but it still has storage attachments.
63+
// UnitHasStorageAttachments describes an error that occurs when trying to
64+
// set a unit's life to Dead but it still has storage attachments.
6365
UnitHasStorageAttachments = errors.ConstError("unit has storage attachments")
6466

65-
// UnitIsAlive describes an error that occurs when trying to remove a unit that is still alive.
67+
// UnitIsAlive describes an error that occurs when trying to remove a unit
68+
// that is still alive.
6669
UnitIsAlive = errors.ConstError("unit is alive")
6770

68-
// InvalidApplicationState describes an error where the application state is invalid.
69-
// There are missing required fields.
71+
// InvalidApplicationState describes an error where the application state is
72+
// invalid. There are missing required fields.
7073
InvalidApplicationState = errors.ConstError("invalid application state")
7174

7275
// CharmNotValid describes an error that occurs when the charm is not valid.
7376
CharmNotValid = errors.ConstError("charm not valid")
7477

75-
// CharmOriginNotValid describes an error that occurs when the charm origin is not valid.
78+
// CharmOriginNotValid describes an error that occurs when the charm origin
79+
// is not valid.
7680
CharmOriginNotValid = errors.ConstError("charm origin not valid")
7781

7882
// CharmNameNotValid describes an error that occurs when attempting to get
@@ -83,7 +87,8 @@ const (
8387
// a charm using an invalid charm source.
8488
CharmSourceNotValid = errors.ConstError("charm source not valid")
8589

86-
// CharmNotFound describes an error that occurs when a charm cannot be found.
90+
// CharmNotFound describes an error that occurs when a charm cannot be
91+
// found.
8792
CharmNotFound = errors.ConstError("charm not found")
8893

8994
// LXDProfileNotFound describes an error that occurs when an LXD profile
@@ -94,16 +99,20 @@ const (
9499
// exists for the given natural key.
95100
CharmAlreadyExists = errors.ConstError("charm already exists")
96101

97-
// CharmRevisionNotValid describes an error that occurs when attempting to get
98-
// a charm using an invalid revision.
102+
// CharmRevisionNotValid describes an error that occurs when attempting to
103+
// get a charm using an invalid revision.
99104
CharmRevisionNotValid = errors.ConstError("charm revision not valid")
100105

101-
// CharmMetadataNotValid describes an error that occurs when the charm metadata
102-
// is not valid.
106+
// CharmMetadataNotValid describes an error that occurs when the charm
107+
// metadata is not valid.
103108
CharmMetadataNotValid = errors.ConstError("charm metadata not valid")
104109

105-
// CharmManifestNotValid describes an error that occurs when the charm manifest
106-
// is not valid.
110+
// CharmManifestNotFound describes an error that occurs when the charm
111+
// manifest is not found.
112+
CharmManifestNotFound = errors.ConstError("charm manifest not found")
113+
114+
// CharmManifestNotValid describes an error that occurs when the charm
115+
// manifest is not valid.
107116
CharmManifestNotValid = errors.ConstError("charm manifest not valid")
108117

109118
// CharmBaseNameNotValid describes an error that occurs when the charm base
@@ -118,18 +127,18 @@ const (
118127
// has multiple relations with the same name
119128
CharmRelationNameConflict = errors.ConstError("charm relation name conflict")
120129

121-
// CharmRelationReservedNameMisuse describes an error that occurs when the charm
122-
// relation name is a reserved name which it is not allowed to use.
130+
// CharmRelationReservedNameMisuse describes an error that occurs when the
131+
// charm relation name is a reserved name which it is not allowed to use.
123132
CharmRelationReservedNameMisuse = errors.ConstError("charm relation reserved name misuse")
124133

125134
// CharmRelationRoleNotValid describes an error that occurs when the charm
126135
// relation roles is not valid. Either it is an unknown role, or it has the
127136
// wrong value.
128137
CharmRelationRoleNotValid = errors.ConstError("charm relation role not valid")
129138

130-
// MultipleCharmHashes describes and error that occurs when a charm has multiple
131-
// hash values. At the moment, we only support sha256 hash format, so if another
132-
// is found, an error is returned.
139+
// MultipleCharmHashes describes and error that occurs when a charm has
140+
// multiple hash values. At the moment, we only support sha256 hash format,
141+
// so if another is found, an error is returned.
133142
MultipleCharmHashes = errors.ConstError("multiple charm hashes found")
134143

135144
// ResourceNotFound describes an error that occurs when a resource is
@@ -169,4 +178,8 @@ const (
169178
// resolved. This means the charm for the hash does not exist and needs to
170179
// be downloaded.
171180
CharmNotResolved = errors.ConstError("charm not resolved")
181+
182+
// CharmDownloadInfoNotFound describes an error that occurs when the charm
183+
// download info is not found.
184+
CharmDownloadInfoNotFound = errors.ConstError("charm download info not found")
172185
)

domain/application/modelmigration/import.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
corestatus "github.com/juju/juju/core/status"
2222
corestorage "github.com/juju/juju/core/storage"
2323
coreunit "github.com/juju/juju/core/unit"
24+
applicationcharm "github.com/juju/juju/domain/application/charm"
2425
"github.com/juju/juju/domain/application/service"
2526
"github.com/juju/juju/domain/application/state"
2627
internalcharm "github.com/juju/juju/internal/charm"
@@ -161,6 +162,12 @@ func (i *importOperation) Execute(ctx context.Context, model description.Model)
161162
err = i.service.ImportApplication(
162163
ctx, app.Name(), charm, *origin, service.AddApplicationArgs{
163164
ReferenceName: chURL.Name,
165+
// TODO (stickupkid): When we're importing a charm during a
166+
// migration, we should fill this in with the correct value.
167+
// If not, we should indicate that the charm can not be
168+
// downloaded without a new request to the charm store to
169+
// fetch the charm.
170+
DownloadInfo: &applicationcharm.DownloadInfo{},
164171
}, unitArgs...,
165172
)
166173
if err != nil {

domain/application/service/application.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ func (s *Service) CreateApplication(
237237
args AddApplicationArgs,
238238
units ...AddUnitArg,
239239
) (coreapplication.ID, error) {
240-
if err := validateCreateApplicationParams(name, args.ReferenceName, charm, origin); err != nil {
240+
if err := validateCreateApplicationParams(name, args.ReferenceName, charm, origin, args.DownloadInfo); err != nil {
241241
return "", errors.Annotatef(err, "invalid application args")
242242
}
243243

@@ -284,23 +284,36 @@ func validateCreateApplicationParams(
284284
name, referenceName string,
285285
charm internalcharm.Charm,
286286
origin corecharm.Origin,
287+
downloadInfo *domaincharm.DownloadInfo,
287288
) error {
288289
if !isValidApplicationName(name) {
289290
return applicationerrors.ApplicationNameNotValid
290291
}
291292

292-
// Validate that we have a valid charm and name.
293-
meta := charm.Meta()
294-
if meta == nil {
293+
// We require a valid charm metadata.
294+
if meta := charm.Meta(); meta == nil {
295295
return applicationerrors.CharmMetadataNotValid
296+
} else if !isValidCharmName(meta.Name) {
297+
return applicationerrors.CharmNameNotValid
296298
}
297299

298-
if !isValidCharmName(meta.Name) {
299-
return applicationerrors.CharmNameNotValid
300-
} else if !isValidReferenceName(referenceName) {
300+
// We require a valid charm manifest.
301+
if manifest := charm.Manifest(); manifest == nil {
302+
return applicationerrors.CharmManifestNotFound
303+
} else if len(manifest.Bases) == 0 {
304+
return applicationerrors.CharmManifestNotValid
305+
}
306+
307+
// If the reference name is provided, it must be valid.
308+
if !isValidReferenceName(referenceName) {
301309
return fmt.Errorf("reference name: %w", applicationerrors.CharmNameNotValid)
302310
}
303311

312+
// If the origin is from charmhub, then we require the download info.
313+
if origin.Source == corecharm.CharmHub && downloadInfo == nil {
314+
return applicationerrors.CharmDownloadInfoNotFound
315+
}
316+
304317
// Validate the origin of the charm.
305318
if err := origin.Validate(); err != nil {
306319
return fmt.Errorf("%w: %v", applicationerrors.CharmOriginNotValid, err)
@@ -372,9 +385,10 @@ func makeCreateApplicationArgs(
372385
}
373386

374387
return application.AddApplicationArg{
375-
Charm: ch,
376-
Platform: platformArg,
377-
Channel: channelArg,
388+
Charm: ch,
389+
CharmDownloadInfo: args.DownloadInfo,
390+
Platform: platformArg,
391+
Channel: channelArg,
378392
}, nil
379393
}
380394

0 commit comments

Comments
 (0)