Ceph RGW lifecycle rules for expiring and tiering objects
Lifecycle rules tell the Ceph Object Gateway when to delete or move objects automatically, so a bucket of logs, backups or archives does not grow without limit and someone does not have to run cleanup jobs by hand. A team needs them when data has a predictable useful life: application logs that are only queried for a few weeks, nightly backups that must be kept for a fixed retention period, or archives that are rarely read after their first months. Rules are attached to a bucket and evaluated against object names, prefixes, tags and age. In plain terms, *expiration* removes an object once its rule condition is met, while *transition* keeps the object but moves it to another storage class or tier, where it may cost less to hold and may take longer to read back. The Ceph Object Gateway (RGW) is the S3-compatible service where these rules run, and its Ceph Object Gateway documentation describes the lifecycle feature and the S3 fields it accepts.
Before writing rules, confirm the exact supported actions, storage class names and tier types against the Squid or Tentacle documentation for the release you run, because lifecycle behavior has changed between releases and this page does not state release-specific behavior. Check how the processing window is scheduled in your environment, since expiration is applied by a background process rather than at the exact moment an object reaches its age. Ask your team to list which buckets will carry rules, which prefixes map to each retention period, and whether any legal hold or audit requirement overrides a deletion date. Test every rule on a non-production bucket with synthetic objects first, and confirm the result with a list operation and a sample of object metadata.
Transition to a remote S3 tier is a one-way move in most designs: once data leaves the local cluster, retrieving it depends on the remote tier and on a restore step, and the local copy may not be returned automatically. Confirm restore behavior, restore latency and the cost of retrieval with the tier provider and your own test before relying on it. Also plan for metadata loss. Object tags, some custom headers, versioning state and certain access settings may not carry across the tier boundary, so inventory the metadata your applications and auditors depend on and verify what survives a round trip. Engage a partner if you need the rule set, tier configuration and restore runbook designed and tested as one deliverable.
Lifecycle actions and when each one fits
This table compares the four lifecycle actions an RGW bucket can run: expiring current objects, expiring noncurrent versions, transitioning to a local storage class, and transitioning to a remote S3 tier. Read each row to see what fires the action, whether it can be undone, and which workloads it suits. The main takeaway is that expiration is generally destructive while transitions move data, so the remote tier deserves the most planning.
| Action | Trigger and reversibility | Main risk | Workload it suits |
|---|---|---|---|
| Expire current objects | Fires when an object's age meets the rule's age condition. Deleted objects are not recoverable unless versioning or backups exist. | Deleting data that applications still read, often because the rule filter was broader than intended. | Logs, temporary exports and scratch data with a documented owner who agrees to the deletion. |
| Expire noncurrent versions | Fires on older versions of an object in a versioned bucket. Reversible only while the noncurrent version still exists. | Storage stays high because delete markers and old versions accumulate if the rule is never added. | Versioned buckets where overwrites are frequent and only the latest copy matters for business use. |
| Transition to a local storage class | Fires on object age and moves data between storage classes in the same cluster. Reversible through a restore or a rewrite by the application. | Expected savings may not appear if placement pools share the same drives, so confirm the target pool's media and cost. | Data that stays in the same cluster but is rarely read, such as older archives kept under the same access controls. |
| Transition to a remote S3 tier | Fires on object age and moves the data to an external S3 endpoint. Reads of tiered objects depend on restore behavior, and the transition is generally one way. | Metadata and some object attributes may not survive the move, and retrieval can be slow or costly, so test the restore path first. | Long-term retention or cold data where the business accepts a restore step and the remote endpoint and its credentials are governed. |
How Ceph RGW lifecycle processing moves objects
A lifecycle rule does not act the moment an object qualifies. Lifecycle rules are attached to a bucket as a configuration set, and the Ceph Object Gateway evaluates them in a background process on a schedule rather than at the time each object is written or ages past a threshold. The practical consequence is that an object can match an expiration or transition condition well before it is removed or moved, and the gap depends on when the lifecycle processor next runs and how much work it has in its window. Before you promise a retention or tiering date to an application team or auditor, confirm the scheduling interval, processing window and any per-bucket or per-rule limits in the Ceph Object Gateway documentation for the release you run, because these values are release-specific and change between versions.
Each rule selects objects through a filter, typically a key prefix, one or more object tags, or a combination of both. Filters decide which objects a rule can touch, so the first design task is to write down which prefixes and tags map to which retention outcome, and to check that no object is expected to match two rules by accident. Where rules overlap, the outcome depends on the actions each rule defines and on how the gateway orders expiration and transition evaluation for the same object. Treat overlap as a defect to be designed out, not as a case the system resolves for you. Build a test bucket with representative keys and tags, set the rules, run the processor (or wait for a documented cycle), and compare the object listing and storage class of each test object against the expected result. Repeat this test whenever a rule changes, and again after any gateway upgrade.
Transition rules move objects to another storage class, and a transition to a remote S3 tier changes where the data physically lives and what the gateway can return on a read. Ask the storage team to document, for each rule, whether the transition is one-way in your release, how a restore is requested and how long it takes, and which object metadata and versions survive the move. Expiration on a versioned bucket needs a separate test, because noncurrent versions and delete markers follow their own rule actions. A rule set that looks correct on paper can still delete or strand data if these interactions are not verified against a real test bucket.
Choosing expiration, local tiering or remote S3 by situation
Temporary exports, build artifacts, upload staging and log spools usually have a clear end of life and no business value after it. For this data, the rule should expire objects, and it should also clean up incomplete multipart uploads, which otherwise keep consuming capacity without appearing in normal listings. The main risk is deleting data that another process still reads, so the owning application team has to sign off on the age threshold before the rule is enabled.
- Owner sign-off: Confirm in writing which application writes and reads the prefix and that nothing depends on objects past the planned expiry.
- Prefix scope: Limit the rule to a documented prefix or tag, not the whole bucket, so a mistyped filter cannot reach unrelated data.
- Multipart cleanup: Include an abort rule for incomplete multipart uploads and confirm the RGW version in your cluster supports the action you configure.
- Dry run on a copy: Apply the same rule to a test bucket with representative object names and check which objects match.
- Evidence: Keep the rule definition in version control, record bucket object counts and capacity before and after the first run, and confirm that expired objects no longer return from a GET.
Ask the application team for the longest legitimate read window they need, because that number, not the storage team's preference, sets the expiry age.
When a policy, contract or regulation sets a minimum retention period, lifecycle expiration becomes a control that auditors will test. The rule must never delete records before the retention period ends, and the rule should be paired with whatever immutability or object-lock behavior your environment provides. DeployOpen can prepare the configuration and evidence, but the retention period and the legal interpretation belong to your compliance and legal owners, and the independent auditor decides whether the control is adequate.
- Retention schedule first: Obtain the written retention period for each data class from the record owner, then map each schedule to a separate bucket or prefix.
- Legal hold interaction: Confirm how holds suspend deletion in your process, because an expiration rule that runs during a hold is a finding.
- Immutability check: Verify with the vendor documentation whether the object lock or versioning features you plan to use are available in your release, and test them before relying on them.
- Change control: Require approval for any change to an expiry age, and log who approved it.
- Evidence: Retain the approved schedule, the rule export, a test showing objects under retention survive the run, and the run logs for the audit period.
Ask your compliance lead which retention clock applies (creation, last modification or event date), since the wrong clock produces early deletion.
Transitioning cold objects to a remote S3-compatible tier can lower local capacity use, but it moves data outside the cluster's control and creates a one-way path in most configurations. Before enabling a transition, the team must understand what the remote tier stores, how restores work, what metadata and tags survive, and who pays for egress and API requests. Treat the remote tier as a separate service with its own failure modes, access model and contract.
- Cost model: Ask the remote provider for storage, request and retrieval charges, then compare them with the local cost of keeping the data. Retrieval and egress charges often decide the outcome.
- Restore behavior: Test restoring a transitioned object end to end, including how long the restore takes and whether the restored copy returns to local storage.
- Metadata loss: Compare object metadata, tags and ACLs before and after transition, and document what does not come back.
- Credentials and network: Confirm the remote endpoint, access keys, TLS trust and firewall path, and record who rotates them.
- Evidence: Keep a transition test report with checksums, restore timings and the documented metadata differences, plus the provider's pricing terms as of the decision date.
Do not enable transitions for data your team may need to reverse, unless you have tested the reverse path.
On a versioned bucket, a lifecycle expiration usually adds a delete marker instead of removing data, so storage keeps growing until noncurrent versions are also expired. Rules must address current versions, noncurrent versions and delete markers separately, and their ages must be chosen with that in mind. Teams often enable an expiry on current objects and assume capacity falls, only to find the noncurrent versions still hold the space.
- Separate actions: Define rules for current expiration, noncurrent version expiration and expired delete marker cleanup, and review each one.
- Noncurrent retention: Confirm how long previous versions must remain for recovery, rollback and compliance, because noncurrent expiry is the step that frees space.
- Delete marker behavior: Test how delete markers appear in listings and whether applications handle them correctly.
- Transition interaction: If noncurrent versions transition to a remote tier, confirm the restore path for a specific older version.
- Evidence: Compare object and version counts plus used capacity over several lifecycle cycles, and keep a sample of listings that show current and noncurrent versions behaving as the rule intends.
Ask the application owners whether any process relies on reading a previous version, because that requirement sets the noncurrent age more than storage cost does.
Setting up lifecycle rules and a remote tier
This sequence takes a Ceph Object Gateway deployment from a confirmed release and configuration to lifecycle rules running on production buckets, with any remote tier tested before data moves. Each step closes with a check of object state, logs or counts, so the team can see exactly what changed. The result is a documented rule set and a record of the transition and restore behavior that applications will depend on.
Confirm the release and gateway configuration
Record the Ceph release running in the cluster and compare it with the active Ceph releases list before any lifecycle work starts. Note the RGW zone, placement targets and storage classes already defined, and identify the S3 client or tool that will send lifecycle calls. Capture the current lifecycle configuration of each candidate bucket as a baseline. Ask the team that operates the gateway to confirm that lifecycle processing is enabled and that no other team is changing these buckets. The step is done when the release, storage classes and baseline are written into the change record.
Create the remote tier endpoint and credentials
Create the target that transitioned objects will move to, whether that is a second storage class on the cluster or a remote S3-compatible endpoint. Create a dedicated account for the tier with only the permissions the transition needs, store its keys in your secrets manager, and keep them out of shell history and configuration files. Confirm that every RGW host trusts the endpoint's TLS certificate. Verify the tier by writing and reading a small test object from a gateway host with those credentials. Ask the remote provider which transition and restore behaviors it supports, because they may differ from the local cluster. The step closes when the test object round-trips successfully.
Test a single-prefix rule on a non-production bucket
Create a non-production bucket and load it with known test objects under one prefix, plus control objects under other prefixes and at the bucket root. Apply a lifecycle rule scoped only to the test prefix, using a clearly labeled test action so results are easy to read without touching live data. Read the configuration back to confirm the rule is stored as written. Check that only objects under the test prefix were affected and that the control objects remain in their original state. The step closes when a listing shows the expected objects transitioned or expired and the control set is unchanged.
Verify the transition and a restore
After lifecycle processing has acted on the test objects, check each transitioned object's storage class and confirm it is served from the tier. Read one object through the gateway and compare its checksum and size with the original. Restore a copy using the restore flow your client supports, then confirm the restored data matches. Compare user metadata, tags and version state before and after the transition, and record anything that does not survive, because applications will lose it when objects move. Review gateway logs for errors from the tier endpoint. The step is done when the transition, restore and metadata comparison are recorded.
Roll out to production buckets in batches
Apply the approved rule to one production bucket at a time, starting with the bucket whose data the team understands best, within a change window the team has agreed. Before each change, confirm the backup or versioning position for that bucket and check that the tier has capacity and working credentials. Apply the rule through the same configuration path used in testing so the outcome matches what was validated. Watch gateway and tier error rates while lifecycle processing runs. Record the bucket, rule and time in the change log, and move to the next bucket only after the previous one shows the expected results.
Monitor counts, sizes and logs after rollout
Establish a baseline of object counts and bytes per bucket on the cluster and on the tier, then compare both after each lifecycle run. Differences should match the rule's scope, and unexplained growth or loss should halt further rollout. Review gateway and tier logs for failed transitions and retry patterns, and route lifecycle and tier errors to your monitoring system as alerts. Confirm that restore requests still succeed for a sample of transitioned objects on a schedule your team sets. Keep the rules, tier configuration and test results together so an auditor or the next operator can trace what changed and when.
What can change or disappear after a transition
Moving an object to a remote S3 tier is not a copy that keeps everything. Several properties stay with the source object, some are rewritten, and some do not travel at all. Test each of the following against your own buckets and your own remote endpoint before any lifecycle rule runs in production.
Object metadata and user attributes
Standard HTTP headers and user-defined metadata are the first thing to verify after a transition. Content type, cache control and custom x-amz-meta-* keys may be preserved, rewritten or dropped depending on the remote S3 implementation and the transition path. Pick a representative set of objects, transition them to a test tier, and compare headers before and after with a HEAD request. Confirm the exact behavior with the remote provider, since Ceph RGW documentation does not guarantee how a foreign endpoint stores these fields.
Tags and object-level settings
Object tags are often used to drive retention, cost allocation and access policy, so losing them quietly breaks downstream rules. Check whether tags are returned on the transitioned object and whether your own tag-based lifecycle filters still match after the move. Ask the remote provider whether tags are stored, how many tags it allows per object, and whether tag changes made after transition are written back to the tier. Verify this in your own environment with a small tagged test set.
ACLs and bucket policies
Bucket policies and ACLs belong to the bucket on each side, so they do not follow the object into the remote tier. A policy that grants read access on the source bucket has no effect on the destination bucket, and the reverse is also true. Inventory every policy and ACL that applies to transitioned data, then confirm which principals can read the remote copy and whether restore requests need separate permissions. Treat the remote provider's policy support as something to confirm, not assume.
Object versions and delete markers
Versioned buckets add a second layer of behavior. Noncurrent versions, delete markers and expiration rules can each trigger a transition, and the remote tier may hold only the version that was transitioned. Test a sequence that includes an overwrite, a delete and a restore, then list versions on both sides. Confirm with the remote provider how it represents versions and whether a delete marker on the source removes the remote copy.
Checksums and encryption state
A transitioned object may arrive with a different checksum representation, or with encryption applied by the remote side rather than by the source. If server-side encryption on the source uses a key your remote provider cannot see, restore may fail or require re-encryption. Record the checksum and encryption headers for test objects before transition, then compare after restore byte for byte. Ask the remote provider which server-side encryption modes it accepts and who holds the keys.
Object naming and lookup behavior
Keys with trailing slashes, unusual characters, or very long prefixes can be normalized differently by a remote S3 service, which changes how listings and lookups behave. Virtual-host and path-style addressing may also differ on the remote endpoint. Run a naming test set that includes these patterns, list prefixes on both sides, and confirm that restores return the exact key. Ask the remote provider about key length limits and how it treats keys that differ only in case or trailing characters.
Restore behavior after a Ceph RGW cloud transition
A transition to a remote tier is one-way from the lifecycle perspective. Once a lifecycle rule has moved an object to the cloud tier, no lifecycle rule moves it back. Bringing data home is a restore, a separate action with its own latency, cost and permission model. Before you rely on a tier, confirm in the Ceph Object Gateway documentation how RGW exposes restore requests to S3 clients, which identities may call them, and whether the application must poll for completion before it can read the object. Treat restore is not a lifecycle function as a design assumption, and map each application that reads archived data to an explicit restore step.
A restored copy is a temporary artifact in most S3-style designs, so its lifetime needs to be planned, not assumed. Confirm how long a restored copy stays readable, whether it counts toward bucket usage and quotas, and whether lifecycle expiration can remove the restored copy, the remote object, or both. Also confirm what happens when an expiration rule fires while a restore is still in progress. Illustrative example: a reporting job restores 200 objects on Monday, and a seven-day expiration rule removes the restored copies before the job finishes on Tuesday. Test this sequence in a staging zone with your own rule set, and make downstream jobs tolerate a second restore if the first copy has already expired.
Reads from a remote provider are billed by that provider, not by Ceph, so they belong in the cost model from the start. Ask the provider for its retrieval charges, request fees, egress pricing and any minimum storage duration for the tier you chose, and confirm whether restores are billed per request, per gigabyte or both. Estimate restore volume from real access patterns, including bursts such as audits or incident reviews. Ask for these terms in writing before you set expiration periods, because a short restored-copy lifetime can cause repeated restores of the same data. Include the contract terms in the written scope so the restore design and its recurring costs are reviewed together.
Security and operations for lifecycle tiers
Lifecycle transitions move data across a trust boundary and expirations remove it for good, so both need the same controls as any other production data path. The cards below cover the credentials, transport, encryption, logging, legal hold and monitoring decisions to settle before the first rule runs.
Least-privilege remote tier credentials
Create a dedicated access key on the remote S3 endpoint that can only write to the tier bucket, with no list, delete or bucket-policy rights unless a specific transition requires them. Scope it to one bucket or prefix, record who holds it, and set a rotation schedule that the RGW tier configuration is updated to match. Confirm with your remote provider how keys are rotated without interrupting transitions in progress.
Encryption in transit and certificate validation
Require HTTPS for the remote tier endpoint and confirm that RGW validates the remote certificate chain against a trusted CA rather than accepting any certificate. Check the hostname matches the endpoint RGW calls, and plan how the CA bundle is updated on every RGW host when the remote provider rotates certificates. A certificate failure shows up as failed transitions, so test it before relying on the tier.
Client-side encryption before transfer
Decide whether objects must be encrypted before they leave the cluster. If the remote provider holds the keys, or your policy requires that tiered data is unreadable to the provider, encrypt objects with keys you control before the transition. Key custody then becomes part of the restore path: a tiered object cannot be read if its key is lost. Ask your security team to document where those keys live and who can release them.
Audit trail for expirations and transitions
Expirations and transitions change or remove data without a client request, so you need evidence of what happened and when. Confirm which RGW logs record lifecycle processing, forward them to your central log store, and keep enough history to answer questions about a deleted object. Define who reviews these records and how a dispute about a missing object is resolved from them.
Legal hold protection from lifecycle rules
Lifecycle rules do not know about legal holds, so a rule can expire data that litigation or an investigation requires. Use the hold mechanism your organization already applies, and check that the lifecycle configuration and the bucket policy prevent expiration for held objects or prefixes. Restrict who can change lifecycle rules, and review rule changes against the list of active holds before they are applied.
Monitoring failed transitions
A transition that fails silently leaves data on the wrong tier, and an expiration that fails leaves data past its retention period. Alert on lifecycle processing errors and on objects that remain in the source class beyond the expected window, and test that the alert fires when the remote endpoint is unreachable. Verify the cluster-level controls in the cluster hardening work before connecting production buckets to a remote tier.
Limits to confirm before enabling transitions
Before you write a transition rule, confirm the limits that decide whether the rule will run at all. The first group is the storage class types your Ceph release supports as transition targets. Ceph's lifecycle transition behavior depends on how the Object Gateway defines storage classes and remote tiers for your release, so the Ceph Object Gateway documentation for your exact release is the authority here, not a general blog post or an older version's notes. Read the lifecycle and storage class sections for that release, and record which tier types are documented as supported, which are partial, and which are absent. Pair that reading with a test on a non-production zone, because documentation can lag behind behavior.
The second group concerns the remote side. Whether a given S3 provider accepts the transition path depends on what that provider implements for object storage classes, restores, and the request types Ceph sends. Ask the provider in writing which storage classes, retrieval behaviors and minimum object sizes or retention rules apply, and confirm that its API accepts the requests your Ceph release generates. Also confirm the provider's charges for early deletion, retrieval and egress, since these recur and can exceed the savings from tiering. Lifecycle filter types, the maximum number of rules per bucket, and how rules interact with multisite replication should be confirmed the same way: check the Ceph release documentation, then verify in your own test environment with a replicated bucket.
The third group is the interaction with object locking and versioning. Expiration and transition behave differently on versioned buckets, and a bucket with object lock or retention settings may refuse an action your rule expects. Test a rule against a versioned, locked bucket and record what happens to current versions, noncurrent versions and delete markers. Assign ownership clearly: the platform team confirms what Ceph does, the storage or compliance owner confirms what the retention policy permits, and the remote provider confirms how it treats locked objects that arrive by transition. Any limit you cannot confirm from documentation should stay disabled in production until your test evidence is written down and reviewed.
Questions teams ask before enabling lifecycle tiering
What drives the cost and effort of a lifecycle rollout?
The largest factors are how many buckets and objects are affected, how many distinct retention and tiering policies the business needs, and how much of the work is design versus configuration. Cost has three parts: design work (inventory, policy decisions, tier selection), build work (rule configuration, remote tier credentials, test harness, monitoring), and ongoing operations (reviewing transitions, handling restore requests, rotating credentials). Setup is largely one-time, while monitoring and periodic review recur. Ask any quote to itemize these phases, to name the buckets and policies in scope, to state which remote S3 endpoint and storage class are assumed, and to say who runs the restore test and how often it repeats.
Can our own team configure lifecycle rules without a partner?
Yes, a capable platform team can write and apply lifecycle rules with the Ceph Object Gateway tooling, provided it has a clear owner for each bucket and a tested retention policy. The harder parts are rarely the rule syntax. They are deciding which prefixes or tags expire, confirming that no application depends on objects that a transition would move out of local storage, and proving that restores behave the way downstream consumers expect. A partner is most useful when those decisions are unresolved, when many teams share a cluster, or when the team wants an independent review before expiring data. Confirm the exact lifecycle features of your Ceph release against the Object Gateway documentation before you commit to a design.
How long do a pilot and a production rollout take?
No duration can be given in general, because the schedule is set by the factors that bound the work: the number of buckets in scope, how well owners respond, whether the remote tier endpoint and credentials already exist, the change window your organization requires, and how many restore tests you must complete before production. A pilot usually covers a small set of non-critical buckets to validate rule behavior, transition timing and restores. Production adds approvals, staged expansion across buckets and monitoring. Ask for a written timeline that names each dependency, the owner of each approval, and the criteria that move a bucket from pilot to production.
What does the work need from our team before it starts?
The work needs four inputs to be in place before design begins:
- A bucket inventory with sizes, object counts, access patterns and the application that writes to each bucket
- A named owner for every bucket who can approve retention and transition rules
- A written retention policy that states what expires, what tiers, and what must never be deleted
- Credentials for the source cluster and for the remote S3 tier, scoped to the minimum actions needed
Missing owners or an unclear retention policy are the most common reasons a rollout stalls. Credentials should be created through your normal secrets process, and the quote should state who provisions and rotates them.
Can a transition to the remote tier be reversed?
Treat transitions as one-way unless your design explicitly plans a return path. A lifecycle transition moves object data to the remote tier and leaves a stub in the source bucket, so the object is not simply moved back by the rule itself. Restoring an object brings back a copy for a period rather than reinstating it as local data, and metadata that the remote tier does not preserve may not return. Before enabling a transition, confirm with the Object Gateway documentation which object attributes survive the round trip, and decide in writing whether a bulk restore to local storage is a supported procedure for your release. Any reversal plan should be tested on a copy, not on production data.
How do we test restores safely before expiring data?
Test restores on non-production copies of representative buckets before any expiration rule touches live data. A useful test covers a small object, a large multipart object, a versioned object, an object with custom metadata and tags, and an object restored after the retention window closes. For each case, record what the client sees: content integrity, metadata, restore latency and any error codes. Keep expiration disabled until the restore results have been reviewed by the bucket owner. Ask any quote to describe the test matrix, the data used, where the test runs, and who signs off on the results.
How DeployOpen scopes and delivers lifecycle and tiering work
DeployOpen plans, builds and documents Ceph RGW lifecycle rules and transition to cloud storage inside infrastructure you control. Each engagement starts from a written scope that names the buckets, rules, remote tier and restore expectations involved.
How we scope
- We inventory buckets, prefixes, object counts and the retention rules each data owner has approved.
- We map which expirations and transitions must run, and which objects must never be expired or moved.
- Engagements are fixed-scope, with deliverables and timelines agreed in writing before any work starts.
How we build
- We configure storage classes and lifecycle rules in a non-production RGW zone first, then review the rule set with your team.
- We test transitions on sample buckets, checking object state, restore calls and the metadata that remains after tiering.
- We record every one-way transition and the approval step required before a rule goes live in production.
How we hand over
- You receive the rule inventory, bucket mapping, remote tier configuration and test results in a handover document.
- We document restore procedures, including who can request a restore and how long a restore is expected to take in your setup.
- Your operators walk through the runbook for adding rules, changing tiers and checking lifecycle processing status.
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer after handover.
- We can review rule changes, remote tier credentials and lifecycle logs when your data owners request new retention policies.
- Ask any provider to confirm which lifecycle features and remote tier types your Ceph release supports before quoting.

